File Coverage

blib/lib/Apache2/AuthNSympa.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::AuthNSympa;
2              
3 1     1   29605 use warnings;
  1         2  
  1         33  
4 1     1   6 use strict;
  1         2  
  1         34  
5 1     1   424 use mod_perl2;
  0            
  0            
6              
7             BEGIN{
8             require Apache2::Const;
9             require Apache2::Access;
10             require Apache2::SubRequest;
11             require Apache2::RequestRec;
12             require Apache2::RequestUtil;
13             require Apache2::Response;
14             require Apache2::Log;
15             use APR::Const -compile => qw(SUCCESS);
16             Apache2::Const->import(-compile => 'HTTP_UNAUTHORIZED','OK', 'AUTH_REQUIRED', 'HTTP_INTERNAL_SERVER_ERROR','DECLINED');
17             require SOAP::Lite;
18             require Cache::Memcached;
19             use Digest::MD5 qw(md5_hex);
20             }
21             =head1 NAME
22              
23             Apache2::AuthNSympa - Authen module using sympa mailing lists server to authenticate
24              
25             =head1 HOMEPAGE
26              
27             L
28              
29             =head1 VERSION
30              
31             Version 0.5.0
32              
33             =cut
34              
35             our $VERSION = '0.5.0';
36              
37             =head1 SYNOPSIS
38              
39             Because it's difficult to have an up to date authentication backend, this module aims to authenticate against Sympa mailing lists server.
40              
41             Sympa mailing lists server has got its own authentication system and can be queried over a SOAP interface.
42              
43             It is based on a basic HTTP authentication (popup on client side). Once the user has authenticated, the REMOTE_USER environnement var contains the user email address. The authentication module implements a SOAP client that validates user credentials against the Sympa SOAP server. Example:
44             Sample httpd.conf example:
45              
46            
47             AuthName SympaAuth
48             AuthType Basic
49             PerlSetVar SympaSoapServer http://mysympa.server/soap
50             PerlSetVar MemcachedServer 10.219.213.24:11211
51             PerlSetVar CacheExptime 3600 # in seconds, default 1800
52              
53             PerlAuthenHandler Apache2::AuthNSympa
54             require valid-user
55              
56            
57              
58             =cut
59             sub handler {
60             my $r = shift;
61            
62             ## Location Variables to connect to the good server
63             my $SympaSoapServer = $r->dir_config('SympaSoapServer') || "localhost"; ## url of sympa soap server
64             my $cacheserver = $r->dir_config('MemcachedServer') || "127.0.0.1:11211"; ## cache server
65             my $exptime = $r->dir_config('CacheExptime') || 1800; ## 30 minutes of cache
66             my $mail_user;
67             my $response;
68             my $result;
69             my $AuthenType = "";
70             my $auth_type = lc($r->auth_type());
71             my $requires = $r->requires;
72             my $location = $r->location();
73              
74             # verify if require valid-user is present, if not, authentication is not for this module
75             for my $entry (@$requires){
76             my $requirement = $entry->{requirement};
77             if ($requirement eq 'valid-user' && $auth_type eq 'basic'){
78             $AuthenType = 'Sympa';
79             $r->log->debug("Apache2::AuthNSympa : require type '$requirement' for $location ","Sympa");
80             last;
81             }else{
82             $r->log->debug("Apache2::AuthNSympa : require type '$requirement' for $location ","other");
83             next;
84             }
85             }
86              
87             if ($AuthenType ne "Sympa"){
88             return Apache2::Const::OK;
89             };
90            
91              
92             ## instanciation of a new Soap::Lite object
93             my $soap;
94             my $soap_session;
95             my $soap_res;
96             my $soap_error=0;
97             unless($soap = new SOAP::Lite()){
98             $r->log_error("Apache2::AuthNSympa : Unable to create SOAP::Lite object while accessing $location");
99             return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
100             }
101              
102             ## if there is an error during soap request. $soap_error will be instanciated
103             $soap->uri('urn:sympasoap');
104             $soap->proxy($SympaSoapServer);
105             $soap->on_fault(sub{
106             ($soap_session, $soap_res) = @_;
107             $soap_error=1;
108             });
109              
110              
111              
112             unless(defined $soap){
113             $r->log_error("Apache2::AuthNSympa : SOAP::Lite undefined");
114             return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
115             }
116              
117              
118            
119             ## instanciation of cache
120             ## preventing from errors, verification of its naming
121             unless( $cacheserver =~ /[^\:]+\:\d{1,6}/){
122             $r->log_error("Apache2::AuthNSympa configuration ($location) : memcached server ($cacheserver) naming format is incorrect, a port number is required");
123             return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
124             }
125            
126             my $cache = new Cache::Memcached {
127             'servers' => [ $cacheserver ],
128             'namespace' => 'AuthNSympa',
129             };
130              
131             ##collect informations from connection
132             my ($status, $password) = $r->get_basic_auth_pw;
133             $mail_user = $r->user;
134             unless ($status == Apache2::Const::OK){
135             $r->note_basic_auth_failure;
136             return $status
137             }
138             unless ($mail_user && $password){
139             $r->note_basic_auth_failure;
140             return Apache2::Const::AUTH_REQUIRED;
141             }
142              
143             ## key generation for cache : md5($mail_user + server name) -> prevents from errors when updating
144             my $user_key = md5_hex($mail_user.$SympaSoapServer);
145             my $hash_pass = md5_hex($password);
146             if (defined $cache){
147             my $cache_pass = $cache->get($user_key);
148             $cache_pass |= "";
149             if ($cache_pass eq $hash_pass){
150             return Apache2::Const::OK;
151             }
152             }
153              
154             ## authentify using SympaSoapServer
155             unless($soap->login($mail_user,$password)){
156             $r->note_basic_auth_failure;
157             return Apache2::Const::DECLINED;
158             }else{
159             $response=$soap->login($mail_user,$password);
160             }
161              
162             ## verify if error during soap service request
163             if ($soap_error==1){
164             my ($type_error,$detail) = &traite_soap_error($soap, $soap_res);
165             if ($type_error eq 'ERROR'){
166             $r->log_error("Apache2::AuthNSympa : SOAP error $detail while accessing $location");
167             }else{
168             $r->log->notice("Apache2::AuthNSympa : $detail ","while accessing $location");
169             };
170              
171             $r->note_basic_auth_failure;
172             return Apache2::Const::HTTP_UNAUTHORIZED;
173             }
174             $result = $response->result;
175             unless($result){
176             $r->log_error("Apache2::AuthNSympa : error, result while accessing $location : $result");
177             $r->note_basic_auth_failure;
178             return Apache2::Const::AUTH_REQUIRED;
179             }
180             ## everything is good, people has authenticated
181              
182             if (defined $cache){
183             $cache->set($user_key, $hash_pass,$exptime);
184             }
185             $r->log->notice("Apache2::AuthNSympa : authentication via $SympaSoapServer for $location");
186             return Apache2::Const::OK;
187            
188             }
189              
190             sub traite_soap_error {
191             my ($soap, $res) = @_;
192             my $detail = "";
193             my $type = "";
194              
195             if(ref(\$res) eq 'REF'){
196             $detail = $res->faultdetail;
197             $type = "NOTICE";
198             }else{
199             $detail = $soap->transport->status;
200             $type = "ERROR";
201             };
202             return ($type, $detail);
203             }
204              
205             =head1 AUTHOR
206              
207             Dominique Launay, Comite Reseau des Universites, C<< >>
208              
209              
210              
211             =head1 COPYRIGHT & LICENSE
212              
213             Copyright 2005 Comite Reseau des Universites, All Rights Reserved.
214              
215             This program is free software; you can redistribute it and/or modify it
216             under the same terms as Perl itself.
217              
218             =cut
219              
220             1; # End of Apache2::AuthNSympa