line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Apache2::AuthZSympa; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
4539
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
4
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
31
|
|
5
|
1
|
|
|
1
|
|
409
|
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 APR::Table; |
15
|
|
|
|
|
|
|
Apache2::Const->import(-compile => 'HTTP_UNAUTHORIZED','OK', 'HTTP_INTERNAL_SERVER_ERROR'); |
16
|
|
|
|
|
|
|
require SOAP::Lite; |
17
|
|
|
|
|
|
|
require Apache2::Log; |
18
|
|
|
|
|
|
|
require Apache2::Directive; |
19
|
|
|
|
|
|
|
require Cache::Memcached; |
20
|
|
|
|
|
|
|
use Digest::MD5 qw(md5_hex); |
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 NAME |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
Apache2::AuthZSympa - Authorization module based on Sympa mailing list server group definition |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 HOMEPAGE |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
L |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 VERSION |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Version 0.5.2 |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=cut |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
our $VERSION = '0.5.2'; |
38
|
|
|
|
|
|
|
=head1 SYNOPSIS |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
This module is an authorization handler for Apache 2. Its authorization method relies on mailing lists membership ; it is designed for Sympa mailing list software (http://sympa.org). This authorization handler has been initially designed to work with its peer authentication handler Apache2::AuthNSympa that performs authentication against a Sympa SOAP server. The handler has later been extended to work with third party authentication Apache modules : |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=over |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=item * |
45
|
|
|
|
|
|
|
Apache2::AuthNSympa (default) |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=item * |
48
|
|
|
|
|
|
|
SSL authentication (mod_ssl) |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=item * |
51
|
|
|
|
|
|
|
CAS authentication (mod_cas) |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=item * |
54
|
|
|
|
|
|
|
Shibboleth authentication (mod_shib) |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=back |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
This module needs the associated authentication handler to provide a trusted user email address ; the user email address is later used to query list membership. Because some authentication modules (CAS) don't provide the user email address, the authorization module may be configured to query an LDAP directory. The environment variable name may also be configured (when used with Shibboleth). |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head1 GENERAL CONFIGURATION TIPS |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
Regardless what authentication module is used, the following rules are needed in your Apache configuration file : |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=over |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=item * |
69
|
|
|
|
|
|
|
URL of your Sympa SOAP server |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=item * |
72
|
|
|
|
|
|
|
list of mailing lists for which the user has to be a member |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=item * |
75
|
|
|
|
|
|
|
handler calling rule |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=item * |
78
|
|
|
|
|
|
|
optionaly, because SOAP can be slow, you can configure a cache server based on memcached (http://www.danga.com/memcached/). |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=back |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
Of course, your mod_perl2 Apache module has to be correctly configured. |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
For example, in a location section of your Apache configuration file, you have to put the following rules : |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
PerlSetVar SympaSoapServer http://mysympa.server/soap # URL of the sympa SOAP server |
87
|
|
|
|
|
|
|
PerlAuthzHandler Apache2::AuthZSympa |
88
|
|
|
|
|
|
|
require SympaLists sympa-users@demo.sympa.org,sympa-test@demo.sympa.org # lists for which the member has to be a member (he needs to be at least a member for one of them) |
89
|
|
|
|
|
|
|
PerlSetVar MemcachedServer 10.219.213.24:11211 # URL for cache server (option) |
90
|
|
|
|
|
|
|
PerlSetVar CacheExptime 3600 # Cache expiration time in seconds for the cache server (default 1800) |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
We provide a working example of a web page that has a restricted access for members of test@cru.fr mailing list only. You should subscribe to the test mailing list if you wish to try it : http://listes.cru.fr/sympa/info/test |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
The following page will request your email address and Sympa password : http://www.cru.fr/demo_authsympa/ |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=head1 SYMPA AUTHENTICATION MODULE |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
It is based on a basic HTTP authentication 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. |
101
|
|
|
|
|
|
|
Example: |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
AuthName SympaAuth |
105
|
|
|
|
|
|
|
AuthType Basic |
106
|
|
|
|
|
|
|
PerlSetVar SympaSoapServer http://mysympa.server/soap |
107
|
|
|
|
|
|
|
PerlAuthenHandler Apache2::AuthNSympa |
108
|
|
|
|
|
|
|
PerlAuthzHandler Apache2::AuthZSympa |
109
|
|
|
|
|
|
|
require valid-user |
110
|
|
|
|
|
|
|
require SympaLists sympa-users@demo.sympa.org,sympa-test@demo.sympa.org |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=head1 SSL AUTHENTICATION |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
Mod_ssl can be used to do the user authentication, based on user client certificates. Your mod_ssl configuration should look like this : |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=over |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=item * |
122
|
|
|
|
|
|
|
SSLCACertificateFile # or SSLCACertificatePath |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=item * |
125
|
|
|
|
|
|
|
SSLRequireSSL # to prevent from disabling SSL |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=item * |
128
|
|
|
|
|
|
|
SSLVerifyClient require |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=item * |
131
|
|
|
|
|
|
|
AuthType SSL |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=back |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Because Apache does not consider mod_ssl as an authentication handler, an authentication handler must be added. So we recommend to call Apache2::AuthNSympa because it is bypassed if "AuthType" is different from "Sympa" |
137
|
|
|
|
|
|
|
The authentication handler will get the expected user email address extracted from the certificate. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Example : |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
SSLVerifyClient require |
143
|
|
|
|
|
|
|
SSLRequireSSL |
144
|
|
|
|
|
|
|
SSLOptions +StdEnvVars |
145
|
|
|
|
|
|
|
AuthType SSL |
146
|
|
|
|
|
|
|
PerlSetVar SympaSoapServer http://mysympa.server/soap |
147
|
|
|
|
|
|
|
PerlAuthenHandler Apache2::AuthNSympa |
148
|
|
|
|
|
|
|
PerlAuthzHandler Apache2::AuthZSympa |
149
|
|
|
|
|
|
|
require SympaLists sympa-users@demo.sympa.org,sympa-test@demo.sympa.org |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=head1 CAS AUTHENTICATION |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
CAS is a web single sign-on software, developped by the university of Yale : http://www.ja-sig.org/products/cas/ |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
CAS does not provide any email address . Therefore the authorization module will first query an LDAP directory to get the user email address, given his UID. |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
Example: |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
AuthName SympaAuth |
165
|
|
|
|
|
|
|
AuthType CAS |
166
|
|
|
|
|
|
|
PerlSetVar SympaSoapServer http://mysympa.server/soap |
167
|
|
|
|
|
|
|
PerlSetVar MemcachedServer 10.219.213.24:11211 |
168
|
|
|
|
|
|
|
PerlSetVar CacheExptime 3600 # in seconds, default 1800 |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
## here is ldap filters to retrieve user email address |
171
|
|
|
|
|
|
|
## if CAS uid is an email address, no need these directives |
172
|
|
|
|
|
|
|
PerlSetVar LDAPHost ldap.localdomain |
173
|
|
|
|
|
|
|
PerlSetVar LDAPSuffix ou=people |
174
|
|
|
|
|
|
|
PerlSetVar LDAPEmailFilter (uid=[uid]) |
175
|
|
|
|
|
|
|
PerlSetVar LDAPEmailAttribute mail |
176
|
|
|
|
|
|
|
PerlSetVar LDAPScope sub |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
PerlAuthzHandler Apache2::AuthZSympa |
179
|
|
|
|
|
|
|
require valid-user |
180
|
|
|
|
|
|
|
require SympaLists sympa-users@demo.sympa.org,sympa-test@demo.sympa.org |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
=head1 SHIBBOLETH AUTHENTICATION |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
Shibboleth is an open source software developped by Internet2 : http://shibboleth.internet2.edu |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
The default behavior of mod_shib authentication module is to provide the user email address in the HTTP_SHIB_INETORGPERSON_MAIL HTTP header. The AuthZSympa module still provides a ShibbolethMailVar parameter to declare which HTTP header contains the user email address, if not the default one. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
The following rules are required: |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=over |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=item * |
196
|
|
|
|
|
|
|
AuthType shibboleth |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=item * |
199
|
|
|
|
|
|
|
require valid-user |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=item * |
202
|
|
|
|
|
|
|
ShibbolethMailVar (if not HTTP_SHIB_INETORGPERSON_MAIL) |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=back |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
Example: |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
AuthType shibboleth |
211
|
|
|
|
|
|
|
PerlSetVar SympaSoapServer http://mysympa.server/soap |
212
|
|
|
|
|
|
|
PerlSetVar MemcachedServer 10.219.213.24:11211 |
213
|
|
|
|
|
|
|
PerlSetVar CacheExptime 3600 # in seconds, default 1800 |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
PerlSetVar ShibbolethMailVar HTTP_SHIB_INETORGPERSON_MAIL |
216
|
|
|
|
|
|
|
PerlAuthzHandler Apache2::AuthZSympa |
217
|
|
|
|
|
|
|
require valid-user |
218
|
|
|
|
|
|
|
require SympaLists sympa-users@demo.sympa.org,sympa-test@demo.sympa.org |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=head1 COMPLETE MODULE RULES LIST |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# required to identify the good authentication type |
226
|
|
|
|
|
|
|
AuthType CAS # can be SSL, Sympa or shibboleth |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# URL to query Sympa server SOAP interface, required |
229
|
|
|
|
|
|
|
PerlSetEnv SympaSoapServer |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# lists to verify membership of user, required |
232
|
|
|
|
|
|
|
require SympaLists list1@mydomain,list2@mydomain |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# IP address and port of memcached server if necessary |
235
|
|
|
|
|
|
|
PerlSetEnv MemcachedServer 192.168.0.1:11211 |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# Cache expiration time in seconds if memcached server used, default 1800 |
238
|
|
|
|
|
|
|
PerlSetEnv CacheExptime 3600 |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# LDAP Host for CAS backend |
241
|
|
|
|
|
|
|
PerlSetEnv LDAPHost ldap.mydomain |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# LDAP suffix to query LDAP backend |
244
|
|
|
|
|
|
|
PerlSetenv LDAPSuffix o=people |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# Filter to query LDAP backend. It has to match uid provided by CAS server |
247
|
|
|
|
|
|
|
PerlSetenv LDAPEmailFilter myIdAttribute=([uid]) |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# LDAP backend attribute containing email address |
250
|
|
|
|
|
|
|
PerlSetenv LDAPEmailAttribute mail |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# LDAP scope, default sub |
253
|
|
|
|
|
|
|
PerlSetenv LDAPScope sub |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
# Shibboleth env var to match email address. optional, default HTTP_SHIB_INETORGPERSON_MAIL |
256
|
|
|
|
|
|
|
PerlSetenv ShibbolethMailVar HTTP_SHIB_INETORGPERSON_MAIL |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=cut |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
sub handler{ |
262
|
|
|
|
|
|
|
my $r= shift; |
263
|
|
|
|
|
|
|
return Apache2::Const::OK unless $r->is_initial_req; |
264
|
|
|
|
|
|
|
## Location Variables to connect to the good server |
265
|
|
|
|
|
|
|
my $SympaSoapServer = $r->dir_config('SympaSoapServer') || "localhost"; ## url of sympa soap server |
266
|
|
|
|
|
|
|
my $cacheserver = $r->dir_config('MemcachedServer') || "127.0.0.1:11211"; ## cache server |
267
|
|
|
|
|
|
|
my $exptime = $r->dir_config('CacheExptime') || 1800; ## 30 minutes of cache |
268
|
|
|
|
|
|
|
my $ShibMailVar = $r->dir_config('ShibbolethMailVar') || 'HTTP_SHIB_INETORGPERSON_MAIL'; |
269
|
|
|
|
|
|
|
my $SympaList = ""; ## list for which the mail will be checked |
270
|
|
|
|
|
|
|
my $mail_user; |
271
|
|
|
|
|
|
|
my $response; |
272
|
|
|
|
|
|
|
my $result; |
273
|
|
|
|
|
|
|
my $auth_type = lc($r->auth_type); |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
my $requires = $r->requires; |
276
|
|
|
|
|
|
|
my $location = $r->location; |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# verify if require SympaLists is present |
281
|
|
|
|
|
|
|
for my $entry (@$requires){ |
282
|
|
|
|
|
|
|
my $requirement; |
283
|
|
|
|
|
|
|
if ($entry->{requirement} =~ /SympaLists/){ |
284
|
|
|
|
|
|
|
($requirement,$SympaList) = split(/\s+/,$entry->{requirement}); |
285
|
|
|
|
|
|
|
$r->log->debug("Apache2::AuthZSympa : require type '$requirement' for $location with lists $SympaList"); |
286
|
|
|
|
|
|
|
last; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
my @SympaLists = split(/\,/,$SympaList); |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
## instanciation of a new Soap::Lite object |
294
|
|
|
|
|
|
|
my $soap; |
295
|
|
|
|
|
|
|
my $soap_error=0; |
296
|
|
|
|
|
|
|
my $soap_session; |
297
|
|
|
|
|
|
|
my $soap_res; |
298
|
|
|
|
|
|
|
unless($soap = new SOAP::Lite()){ |
299
|
|
|
|
|
|
|
$r->log_error("Apache2::AuthZSympa : Unable to create SOAP::Lite object while accessing $location"); |
300
|
|
|
|
|
|
|
return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
## if there is an error during soap request. $soap_error will be instanciated |
303
|
|
|
|
|
|
|
$soap->on_fault(sub { |
304
|
|
|
|
|
|
|
($soap_session, $soap_res) = @_; |
305
|
|
|
|
|
|
|
$soap_error=1; |
306
|
|
|
|
|
|
|
}); |
307
|
|
|
|
|
|
|
$soap->uri('urn:sympasoap'); |
308
|
|
|
|
|
|
|
$soap->proxy($SympaSoapServer); |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
unless(defined $soap){ |
312
|
|
|
|
|
|
|
return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
## instanciation of cache |
316
|
|
|
|
|
|
|
## preventing from errors, verification of its naming |
317
|
|
|
|
|
|
|
unless( $cacheserver =~ /[^\:]+\:\d{1,6}/){ |
318
|
|
|
|
|
|
|
$r->log_error("Apache2::AuthZSympa configuration ($location) : memcached server ($cacheserver) naming format is incorrect, a port number is required"); |
319
|
|
|
|
|
|
|
return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
my $cache = new Cache::Memcached { |
322
|
|
|
|
|
|
|
'servers' => [ $cacheserver ], |
323
|
|
|
|
|
|
|
'namespace' => 'AuthZSympa', |
324
|
|
|
|
|
|
|
}; |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
## if an email from SSL request is got, then authentication was made via SSL |
329
|
|
|
|
|
|
|
$r->subprocess_env; |
330
|
|
|
|
|
|
|
my $subr = $r->lookup_uri($r->uri); |
331
|
|
|
|
|
|
|
my $ssl_proto = $subr->subprocess_env('SSL_CLIENT_S_DN_Email'); |
332
|
|
|
|
|
|
|
if ($subr->subprocess_env('SSL_CLIENT_S_DN_Email') && ($auth_type eq "ssl")){ |
333
|
|
|
|
|
|
|
$mail_user=$subr->subprocess_env('SSL_CLIENT_S_DN_Email'); |
334
|
|
|
|
|
|
|
$r->user($mail_user); |
335
|
|
|
|
|
|
|
}elsif($auth_type eq 'basic' && $r->user){ |
336
|
|
|
|
|
|
|
## if basic_auth, get remote_user |
337
|
|
|
|
|
|
|
$mail_user= $r->user; |
338
|
|
|
|
|
|
|
}elsif($auth_type eq 'cas'){ |
339
|
|
|
|
|
|
|
## if CAS |
340
|
|
|
|
|
|
|
my $user = $r->user; |
341
|
|
|
|
|
|
|
$mail_user = ""; |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
## verification of ldap directives |
344
|
|
|
|
|
|
|
my $ldap_host = $r->dir_config('LDAPHost') || ""; |
345
|
|
|
|
|
|
|
if ($ldap_host eq ""){ |
346
|
|
|
|
|
|
|
$r->log->debug("Apache2::AuthZSympa : no LDAPHost, email adress in uid ?"); |
347
|
|
|
|
|
|
|
if ($user =~ /@/){ |
348
|
|
|
|
|
|
|
## if user is emailAddress, don't need ldap to retrieve emailadddress |
349
|
|
|
|
|
|
|
$r->log->debug("Apache2::AuthZSympa : no need with LDAP, email adress in uid"); |
350
|
|
|
|
|
|
|
$mail_user = $user; |
351
|
|
|
|
|
|
|
}else{ |
352
|
|
|
|
|
|
|
$r->log_error("Apache2::AuthZSympa : no ldap_host defined for $location, can't verify registrations"); |
353
|
|
|
|
|
|
|
return Apache2::Const::HTTP_UNAUTHORIZED; |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
## key for cache (key for email) |
357
|
|
|
|
|
|
|
my $user_key = md5_hex($r->user.$ldap_host); |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
## verification first in cache |
361
|
|
|
|
|
|
|
if (defined $cache->get($user_key)){ |
362
|
|
|
|
|
|
|
$r->log->debug("Apache2::AuthZSympa : retrieve mail from cache for $user_key"); |
363
|
|
|
|
|
|
|
$mail_user = ${$cache->get($user_key)}; |
364
|
|
|
|
|
|
|
$r->log->debug("Apache2::AuthZSympa : retrieved mail ($mail_user) from cache") if $mail_user ne ""; |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
## then retrieve mail from ldap |
367
|
|
|
|
|
|
|
if ($mail_user eq ""){ |
368
|
|
|
|
|
|
|
$r->log->debug("Apache2::AuthZSympa : retrieve mail from LDAP"); |
369
|
|
|
|
|
|
|
$mail_user = &casGetMail($r); |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
if ($mail_user ne ""){ |
372
|
|
|
|
|
|
|
$r->log->debug("Apache2::AuthZSympa : retrieved mail $mail_user"); |
373
|
|
|
|
|
|
|
$cache->set($user_key,\$mail_user,$exptime); |
374
|
|
|
|
|
|
|
}else{ |
375
|
|
|
|
|
|
|
$r->log_error("Apache2::AuthZSympa : no mail for $user in $ldap_host"); |
376
|
|
|
|
|
|
|
return Apache2::Const::HTTP_UNAUTHORIZED; |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
}elsif($auth_type eq 'shibboleth'){ |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
$mail_user=$ENV{$ShibMailVar}; |
382
|
|
|
|
|
|
|
if($mail_user eq ""){ |
383
|
|
|
|
|
|
|
$r->log_error("Apache2::AuthZSympa : no mail in var $ShibMailVar"); |
384
|
|
|
|
|
|
|
$r->log->debug("Apache2::AuthZSympa : $ShibMailVar value : $mail_user"); |
385
|
|
|
|
|
|
|
return Apache2::Const::HTTP_UNAUTHORIZED; |
386
|
|
|
|
|
|
|
}else{ |
387
|
|
|
|
|
|
|
$r->log->debug("Apache2::AuthZSympa : $ShibMailVar value : $mail_user"); |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
}else{ |
391
|
|
|
|
|
|
|
$r->log_error("Apache2::AuthZSympa : no user authenticated for $location, can't verify registrations"); |
392
|
|
|
|
|
|
|
return Apache2::Const::HTTP_UNAUTHORIZED; |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
## key generation for cache : md5($mail_user + server name) -> prevents from errors when updating |
396
|
|
|
|
|
|
|
my $user_key = md5_hex($mail_user.$SympaSoapServer); |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
## verify subscription first in cache |
399
|
|
|
|
|
|
|
## if its in the cache as OK for the list, go, |
400
|
|
|
|
|
|
|
## if its in all the list as not OK, refuse |
401
|
|
|
|
|
|
|
## else, next step |
402
|
|
|
|
|
|
|
my %cache_lists; |
403
|
|
|
|
|
|
|
if (defined $cache){ |
404
|
|
|
|
|
|
|
if (defined $cache->get($user_key)){ |
405
|
|
|
|
|
|
|
%cache_lists = %{$cache->get($user_key)}; |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
my $ok=1; |
408
|
|
|
|
|
|
|
foreach my $list (@SympaLists){ |
409
|
|
|
|
|
|
|
if (defined $cache_lists{$list}){ |
410
|
|
|
|
|
|
|
if ($cache_lists{$list} == 1){ |
411
|
|
|
|
|
|
|
return Apache2::Const::OK; |
412
|
|
|
|
|
|
|
}elsif($cache_lists{$list} == 0){ |
413
|
|
|
|
|
|
|
$ok = 0; |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
if ($ok == 0){ |
418
|
|
|
|
|
|
|
my $lists_string = join(", nor in ",@SympaLists); |
419
|
|
|
|
|
|
|
$r->log->notice("Apache2::AuthZSympa : $location. $mail_user is not registred on server $SympaSoapServer in ",$lists_string); |
420
|
|
|
|
|
|
|
return Apache2::Const::HTTP_UNAUTHORIZED; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
## if not in cache, verify soap server |
424
|
|
|
|
|
|
|
foreach my $list (@SympaLists){ |
425
|
|
|
|
|
|
|
$r->log->debug("Apache2::AuthZSympa liste $list"); |
426
|
|
|
|
|
|
|
$soap_error=0; |
427
|
|
|
|
|
|
|
$list =~ s/\s//g; |
428
|
|
|
|
|
|
|
$response = $soap->amI($list,'subscriber',$mail_user); |
429
|
|
|
|
|
|
|
## verify if error during soap service request |
430
|
|
|
|
|
|
|
if ($soap_error==1){ |
431
|
|
|
|
|
|
|
my ($type_error,$detail) = &traite_soap_error($soap, $soap_res); |
432
|
|
|
|
|
|
|
if ($type_error eq 'ERROR'){ |
433
|
|
|
|
|
|
|
$r->log_error("Apache2::AuthZSympa : $location, SOAP error $detail (server $SympaSoapServer)"); |
434
|
|
|
|
|
|
|
}else{ |
435
|
|
|
|
|
|
|
$r->log->notice("Apache2::AuthZSympa : $location, $detail (server $SympaSoapServer)"); |
436
|
|
|
|
|
|
|
}; |
437
|
|
|
|
|
|
|
$cache_lists{$list} = 0; |
438
|
|
|
|
|
|
|
next; |
439
|
|
|
|
|
|
|
}else{ |
440
|
|
|
|
|
|
|
$result = $response->result; |
441
|
|
|
|
|
|
|
if ($result == 1){ |
442
|
|
|
|
|
|
|
if (defined $cache){ |
443
|
|
|
|
|
|
|
$cache_lists{$list} = 1; |
444
|
|
|
|
|
|
|
$cache->set($user_key, \%cache_lists,$exptime); |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
return Apache2::Const::OK; |
447
|
|
|
|
|
|
|
}else{ |
448
|
|
|
|
|
|
|
$cache_lists{$list} = 0; |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
$cache->set($user_key, \%cache_lists,$exptime); |
453
|
|
|
|
|
|
|
my $lists_string = join(", nor in ",@SympaLists); |
454
|
|
|
|
|
|
|
$r->log->notice("Apache2::AuthZSympa : $location. $mail_user is not registred on server $SympaSoapServer in ",$lists_string); |
455
|
|
|
|
|
|
|
return Apache2::Const::HTTP_UNAUTHORIZED; |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
sub traite_soap_error { |
461
|
|
|
|
|
|
|
my ($soap, $res) = @_; |
462
|
|
|
|
|
|
|
my $detail = ""; |
463
|
|
|
|
|
|
|
my $type = ""; |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
if(ref(\$res) eq 'REF'){ |
466
|
|
|
|
|
|
|
$detail = $res->faultdetail; |
467
|
|
|
|
|
|
|
$type = "NOTICE"; |
468
|
|
|
|
|
|
|
}else{ |
469
|
|
|
|
|
|
|
$detail = $soap->transport->status; |
470
|
|
|
|
|
|
|
$type = "ERROR"; |
471
|
|
|
|
|
|
|
}; |
472
|
|
|
|
|
|
|
return ($type, $detail); |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
sub casGetMail(){ |
476
|
|
|
|
|
|
|
my ($r) = @_; |
477
|
|
|
|
|
|
|
my $error=""; |
478
|
|
|
|
|
|
|
use Net::LDAP; |
479
|
|
|
|
|
|
|
my $user = $r->user; |
480
|
|
|
|
|
|
|
my $ldap_host = $r->dir_config('LDAPHost'); |
481
|
|
|
|
|
|
|
my $ldap_suffix = $r->dir_config('LDAPSuffix'); |
482
|
|
|
|
|
|
|
my $uid_filter = $r->dir_config('LDAPEmailFilter'); |
483
|
|
|
|
|
|
|
my $attribute = $r->dir_config('LDAPEmailAttribute'); |
484
|
|
|
|
|
|
|
my $scope = $r->dir_config('LDAPScope') || "sub"; |
485
|
|
|
|
|
|
|
my $location = $r->location; |
486
|
|
|
|
|
|
|
my $ldap; |
487
|
|
|
|
|
|
|
unless($ldap = Net::LDAP->new($ldap_host)){ |
488
|
|
|
|
|
|
|
$r->log_error("Apache2::AuthZSympa : $location, unable to create Net::LDAP object with $ldap_host"); |
489
|
|
|
|
|
|
|
return ""; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
my $mesg; |
492
|
|
|
|
|
|
|
unless($mesg = $ldap->bind){ |
493
|
|
|
|
|
|
|
$r->log_error("Apache2::AuthZSympa : $location, unable to bind $ldap_host"); |
494
|
|
|
|
|
|
|
return ""; |
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
my $filter = $uid_filter; |
497
|
|
|
|
|
|
|
$filter =~ s/\[uid\]/$user/; |
498
|
|
|
|
|
|
|
$mesg = $ldap->search( # perform a search |
499
|
|
|
|
|
|
|
base => $ldap_suffix, |
500
|
|
|
|
|
|
|
scope => $scope, |
501
|
|
|
|
|
|
|
attrs => [$attribute], |
502
|
|
|
|
|
|
|
filter => $filter, |
503
|
|
|
|
|
|
|
); |
504
|
|
|
|
|
|
|
my $nb_entries = $mesg->count; |
505
|
|
|
|
|
|
|
if(($nb_entries == 0) | ($nb_entries>1)){ |
506
|
|
|
|
|
|
|
$r->log->notice("Apache2::AuthZSympa : $location, $nb_entries entries returned while querying $ldap_host, maybe wrong parameter ?"); |
507
|
|
|
|
|
|
|
$ldap->unbind; |
508
|
|
|
|
|
|
|
return ""; |
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
my $entry = $mesg->entry(0); |
511
|
|
|
|
|
|
|
my $mail_user = $entry->get_value($attribute); |
512
|
|
|
|
|
|
|
$ldap->unbind; |
513
|
|
|
|
|
|
|
return $mail_user; |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
=head1 AUTHOR |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
Dominique Launay,Comite Reseau des Universites, C<< >> |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
Copyright 2005 Comite Reseau des Universites L All Rights Reserved. |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
526
|
|
|
|
|
|
|
under the same terms as Perl itself. |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=cut |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
1; # End of Apache2::AuthZSympa |