Handler.pm 9.92 KB
Newer Older
1
2
package Lemonldap::NG::Handler;

Yadd's avatar
Yadd committed
3
4
print STDERR
"See Lemonldap::NG::Handler(3) to know which Lemonldap::NG::Handler::* module to use.";
Yadd's avatar
Yadd committed
5
our $VERSION = "0.74";
6
7
8
9
10
11
12
13
14

1;

__END__

=pod

=head1 NAME

Yadd's avatar
Yadd committed
15
16
Lemonldap::NG::Handler - The Apache protection module part of
Lemonldap::NG Web-SSO system.
17
18
19
20
21
22
23
24

=head1 SYNOPSIS

=head2 Create your Apache module

Create your own package (example using a central configuration database):

  package My::Package;
Yadd's avatar
Yadd committed
25
26
  use Lemonldap::NG::Handler::SharedConf;
  @ISA = qw(Lemonldap::NG::Handler::SharedConf);
27
28
29
30
31
32
  
  __PACKAGE__->init ( {
    # Local storage used for sessions and configuration
    localStorage        => "Cache::DBFile",
    localStorageOptions => {...},
    # How to get my configuration
Yadd's avatar
Yadd committed
33
34
35
36
37
38
    configStorage       => {
        type                => "DBI",
        dbiChain            => "DBI:mysql:database=lemondb;host=$hostname",
        dbiUser             => "lemonldap",
        dbiPassword          => "password",
    }
39
40
41
42
43
44
45
46
47
  } );

=head2 Configure Apache

Call your package in /apache-dir/conf/httpd.conf:

  # Load your package
  PerlRequire /My/File
  # TOTAL PROTECTION
48
  PerlHeaderParserHandler My::Package
49
50
  # OR SELECTED AREA
  <Location /protected-area>
51
    PerlHeaderParserHandler My::Package
52
53
54
55
56
57
58
59
60
61
  </Location>

The configuration is loaded only at Apache start. Create an URI to force
configuration reload, so you don't need to restart Apache at each change:

  # /apache-dir/conf/httpd.conf
  <Location /location/that/I/ve/choosed>
    Order deny,allow
    Deny from all
    Allow from my.manager.com
62
    PerlHeaderParserHandler My::Package->refresh
63
  </Location>
Yadd's avatar
Yadd committed
64
65
66
67
68
69
70
  
You can also unprotect an URI

  <Files "*.gif">
    PerlHeaderParserHandler My::Package->unprotect
  </Files>

71
72
73
74
75
76
77
78
79
80

=head1 DESCRIPTION

Lemonldap::NG is a modular Web-SSO based on Apache::Session modules. It
simplifies the build of a protected area with a few changes in the application.

It manages both authentication and authorization and provides headers for
accounting. So you can have a full AAA protection for your web space as
described below.

Yadd's avatar
Yadd committed
81
The Apache module part works both with Apache 1.3.x and 2.x ie mod_perl 1 and 2
Yadd's avatar
Yadd committed
82
but B<not with mod_perl 1.99>.
83

Yadd's avatar
Yadd committed
84
=head2 Authentication, Authorization, Accounting
85
86
87
88
89
90
91
92
93
94
95
96
97

=head3 B<Authentication>

If a user isn't authenticated and attemps to connect to an area protected by a
Lemonldap::NG compatible handler, he is redirected to a portal. The portal
authenticates user with a ldap bind by default, but you can also use another
authentication sheme like using x509 user certificates (see
L<Lemonldap::NG::Portal::AuthSSL> for more).

Lemonldap use session cookies generated by L<Apache::Session> so as secure as a
128-bit random cookie. You may use the C<securedCookie> options of
L<Lemonldap::NG::Portal> to avoid session hijacking.

Yadd's avatar
Yadd committed
98
99
100
101
You have to manage life of sessions by yourself since Lemonldap::NG knows
nothing about the L<Apache::Session> module you've choosed, but it's very easy
using a simple cron script because L<Lemonldap::NG::Portal> stores the start
time in the C<_utime> field.
102
103
104
105
106
107
108
109
110
111
112
113
114
115
By default, a session stay 10 minutes in the local storage, so in the worth
case, a user is authorized 10 minutes after he lost his rights.

=head3 B<Authorization>

Authorization is controled only by handlers because the portal knows nothing
about the way the user will choose. When configuring your Web-SSO, you have to:

=over

=item * choose the ldap attributes you want to use to manage accounting and
authorization (see C<exportedHeaders> parameter in L<Lemonldap::NG::Portal>
documentation).

Yadd's avatar
Yadd committed
116
=item * create Perl expressions to define user groups (using ldap attributes)
117
118
119
120
121
122

=item * create an array foreach virtual host associating URI regular
expressions and Perl expressions to use to grant access.

=back

Yadd's avatar
Yadd committed
123
124
=head4 Example (See L<Lemonldap::NG::Manager> to see how configuration is
stored)
125

Yadd's avatar
Yadd committed
126
127
Exported variables (values will be stored in session database by
L<Lemonldap::NG::Portal>):
128
129
130
131
132
133
134

  exportedVars => {
      cn            => "cn",
      departmentUID => "departmentUID",
      login         => "uid",
  },

Yadd's avatar
Yadd committed
135
136
User groups (values will be stored in session database by
L<Lemonldap::NG::Portal>):
137
138
139
140
141
142

  groups => {
      group1 => '{ $departmentUID eq "unit1" or $login = "xavier.guimard" }',
      ...
  },

Yadd's avatar
Yadd committed
143
Area protection:
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159

  locationRules => {
      www1.domain.com => {
          '^/protected/.*$' => '$groups =~ /\bgroup1\b/',
          default           => 'accept',
      },
      www2.domain.com => {
          '^/site/.*$' => '$uid eq "xavier.guimard" or $groups =~ /\bgroup2\b/',
          '^/(js|css)' => 'accept',
          default      => 'deny',
      },
  },

=head4 Performance

You can use Perl expressions as complicated as you want and you can use all
Yadd's avatar
Yadd committed
160
161
162
the exported LDAP attributes (and create your own attributes: with 'macros'
mechanism. See L<Lemonldap::NG::Manager>) in groups evaluations, area
protections or custom HTTP headers (you just have to call them with a "$").
163
164
165
166
167

You have to be careful when choosing your expressions:

=over

Yadd's avatar
Yadd committed
168
169
=item * C<groups> and C<macros> are evaluated each time a user is redirected to
the portal,
170

Yadd's avatar
Yadd committed
171
172
=item * C<locationRules> and C<exportedheaders> are evaluated for each request
on a protected area.
173
174
175
176
177
178
179
180
181
182
183
184

=back

It is also recommanded to use the C<groups> mechanism to avoid having to
evaluate a long expression at each HTTP request:

  locationRules => {
      www1.domain.com => {
          '^/protected/.*$' => '$groups =~ /\bgroup1\b/',
      },
  },

Yadd's avatar
Yadd committed
185
186
You can also use LDAP filters, or Perl expression or mixed expressions in
C<groups> parameter. Perl expressions has to be enclosed with C<{}>:
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

=over

=item * C<group1 =E<gt> '(|(uid=xavier.guimard)(ou=unit1))'>

=item * C<group1 =E<gt> '{$uid eq "xavier.guimard" or $ou eq "unit1"}'>

=item * C<group1 =E<gt> '(|(uid=xavier.guimard){$ou eq "unit1"})'>

=back

It is also recommanded to use Perl expressions to avoid requiering the LDAP
server more than 2 times per authentication.

=head3 B<Accounting>

=head4 I<Logging portal access>

L<Lemonldap::NG::Portal> doesn't log anything by default, but it's easy to overload
C<log> method for normal portal access or using C<error> method to know what
was wrong if C<process> method has failed.

=head4 I<Logging application access>

Because an handler knows nothing about the protected application, it can't do
Yadd's avatar
Yadd committed
212
213
214
more than logging URL. As Apache does this fine, L<Lemonldap::NG::Handler>
gives it the name to used in logs. The C<whatToTrace> parameters indicates
which variable Apache has to use (C<$uid> by default).
215
216
217
218

The real accounting has to be done by the application itself which knows the
result of SQL transaction for example.

Yadd's avatar
Yadd committed
219
220
221
222
223
Lemonldap::NG can export HTTP headers either using a proxy or protecting
directly the application. By default, the C<Auth-User> field is used but you
can change it using the C<exportedHeaders> parameters (stored in the
configuration database). This parameters contains an associative array per
virtual host:
224
225
226
227
228

=over

=item * B<keys> are the names of the choosen headers

Yadd's avatar
Yadd committed
229
=item * B<values> are Perl expressions where you can use user datas stored in
230
231
232
233
234
235
236
237
238
239
240
241
242
the global store by calling them C<$E<lt>varnameE<gt>>.

=back

Example:

  exportedHeaders => {
      www1.domain.com => {
          'Auth-User' => '$uid',
          'Unit'      => '$ou',
      },
      www2.domain.com => {
          'Authorization' => '"Basic ".encode_base64($employeeNumber.":dummy")',
Yadd's avatar
Yadd committed
243
          'Remote-IP'     => '$ip',
244
245
246
      },
  }

Yadd's avatar
Yadd committed
247
=head2 Session storage systems
248
249
250
251
252
253
254
255
256
257

Lemonldap::NG use 3 levels of cache for authenticated users:

=over

=item * an Apache::Session::* module choosed with the C<globalStorage>
parameter (completed with C<globalStorageOptions>) and used by
L<lemonldap::NG::Portal> to store authenticated user parameters,

=item * a L<Cache::Cache> module choosed with the C<localStorage> parameter
Yadd's avatar
Yadd committed
258
(completed with C<localStorageOptions>) and used to share authenticated users
259
260
between Apache's threads or processus and of course between virtual hosts,

Yadd's avatar
Yadd committed
261
262
263
=item * Lemonldap::NG::Handler variables: if the same user use the same thread
or processus a second time, no request are needed to grant or refuse access.
This is very efficient with HTTP/1.1 Keep-Alive system.
264
265
266

=back

Yadd's avatar
Yadd committed
267
268
So the number of request to the central storage is limited to 1 per active
user each 10 minutes.
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301

Lemonldap::NG is very fast, but you can increase performance using a
L<Cache::Cache> module that does not use disk access.

=head1 USING LEMONLDAP::NG::HANDLER FOR DEVELOPMENT

Lemonldap::NG::Handler provides different modules:

=over

=item * L<Lemonldap::NG::Handler::Simple>: base module. It can be used
directly to protect a single host.

=item * L<Lemonldap::NG::Handler::Vhost>: module used to managed virtual hosts.

=item * L<Lemonldap::NG::Handler::SharedConf>: with this module, the
configuration can be centralized. Inherits from
L<Lemonldap::NG::Handler::Vhost> and L<Lemonldap::NG::Handler::Simple>.

=item * L<Lemonldap::NG::Handler::Proxy>: this module isn't used to manage
security but is written to create a reverse-proxy without using mod_proxy. In
some case, mod_proxy does not manage correctly some redirections, that is why
this module still exists.

=back

All those modules are compatible both with Apache and mod_perl version 1 and 2,
but NOT with mod_perl 1.99. If you use Linux distributions like Debian Sarge
who provide mod_perl 1.99 for Apache2, you have to use Apache-1.3 or to
download a mod_perl2 backport.

=head1 SEE ALSO

Yadd's avatar
Yadd committed
302
L<Lemonldap::NG::Handler::SharedConf>,
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
L<Lemonldap::NG::Portal>, L<Lemonldap::NG::Manager>

=head1 AUTHOR

Xavier Guimard, E<lt>x.guimard@free.frE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2005 by Xavier Guimard E<lt>x.guimard@free.frE<gt>

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.4 or,
at your option, any later version of Perl 5 you may have available.

Lemonldap was originaly written by Eric German who decided to publish him in
2003 under the terms of the GNU General Public License version 2.
Lemonldap::NG is a complete rewrite of Lemonldap and is able to have different
policies in a same Apache virtual host.

=cut