|
|
|
@ -356,347 +356,3 @@ sub setPostParams { |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
=pod |
|
|
|
|
|
|
|
|
|
=encoding utf8 |
|
|
|
|
|
|
|
|
|
=head1 NAME |
|
|
|
|
|
|
|
|
|
Lemonldap::NG::Handler - The Apache protection module part of |
|
|
|
|
Lemonldap::NG Web-SSO system. |
|
|
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
|
|
|
|
|
|
|
|
=head2 Configure Apache |
|
|
|
|
|
|
|
|
|
Call Handler in /apache-dir/conf/httpd.conf: |
|
|
|
|
|
|
|
|
|
# Load your package |
|
|
|
|
PerlRequire /My/File |
|
|
|
|
# TOTAL PROTECTION |
|
|
|
|
PerlHeaderParserHandler Lemonldap::NG::Handler::DefaultHandler |
|
|
|
|
# OR SELECTED AREA |
|
|
|
|
<Location /protected-area> |
|
|
|
|
PerlHeaderParserHandler Lemonldap::NG::Handler::DefaultHandler |
|
|
|
|
</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 |
|
|
|
|
PerlHeaderParserHandler Lemonldap::NG::Handler::DefaultHandler->refresh |
|
|
|
|
</Location> |
|
|
|
|
|
|
|
|
|
To display the status page, add something like this : |
|
|
|
|
|
|
|
|
|
<Location /status> |
|
|
|
|
Order deny,allow |
|
|
|
|
Allow from 10.1.1.0/24 |
|
|
|
|
Deny from all |
|
|
|
|
PerlHeaderParserHandler Lemonldap::NG::Handler::DefaultHandler->status |
|
|
|
|
</Location> |
|
|
|
|
|
|
|
|
|
=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. |
|
|
|
|
|
|
|
|
|
The Apache module part works both with Apache 1.3.x and 2.x ie mod_perl 1 and 2 |
|
|
|
|
but B<not with mod_perl 1.99>. |
|
|
|
|
|
|
|
|
|
=head2 Authentication, Authorization, Accounting |
|
|
|
|
|
|
|
|
|
=head3 B<Authentication> |
|
|
|
|
|
|
|
|
|
If a user isn't authenticated and attempts 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::NG 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. |
|
|
|
|
|
|
|
|
|
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. |
|
|
|
|
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 controlled 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). |
|
|
|
|
|
|
|
|
|
=item * create Perl expressions to define user groups (using ldap attributes) |
|
|
|
|
|
|
|
|
|
=item * create an array foreach virtual host associating URI regular |
|
|
|
|
expressions and Perl expressions to use to grant access. |
|
|
|
|
|
|
|
|
|
=back |
|
|
|
|
|
|
|
|
|
=head4 Example (See L<Lemonldap::NG::Manager> to see how configuration is |
|
|
|
|
stored) |
|
|
|
|
|
|
|
|
|
Exported variables (values will be stored in session database by |
|
|
|
|
L<Lemonldap::NG::Portal>): |
|
|
|
|
|
|
|
|
|
exportedVars => { |
|
|
|
|
cn => "cn", |
|
|
|
|
departmentUID => "departmentUID", |
|
|
|
|
login => "uid", |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
User groups (values will be stored in session database by |
|
|
|
|
L<Lemonldap::NG::Portal>): |
|
|
|
|
|
|
|
|
|
groups => { |
|
|
|
|
group1 => '{ $departmentUID eq "unit1" or $login = "xavier.guimard" }', |
|
|
|
|
... |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
Area protection: |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
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 "$"). |
|
|
|
|
|
|
|
|
|
You have to be careful when choosing your expressions: |
|
|
|
|
|
|
|
|
|
=over |
|
|
|
|
|
|
|
|
|
=item * C<groups> and C<macros> are evaluated each time a user is redirected to |
|
|
|
|
the portal, |
|
|
|
|
|
|
|
|
|
=item * C<locationRules> and C<exportedheaders> are evaluated for each request |
|
|
|
|
on a protected area. |
|
|
|
|
|
|
|
|
|
=back |
|
|
|
|
|
|
|
|
|
It is also recommended 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/', |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
You can also use LDAP filters, or Perl expression or mixed expressions in |
|
|
|
|
C<groups> parameter. Perl expressions has to be enclosed with C<{}>: |
|
|
|
|
|
|
|
|
|
=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 recommended to use Perl expressions to avoid requiring 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 |
|
|
|
|
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). |
|
|
|
|
|
|
|
|
|
The real accounting has to be done by the application itself which knows the |
|
|
|
|
result of SQL transaction for example. |
|
|
|
|
|
|
|
|
|
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: |
|
|
|
|
|
|
|
|
|
=over |
|
|
|
|
|
|
|
|
|
=item * B<keys> are the names of the chosen headers |
|
|
|
|
|
|
|
|
|
=item * B<values> are Perl expressions where you can use user datas stored in |
|
|
|
|
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","")', |
|
|
|
|
'Remote-IP' => '$ip', |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
=head2 Session storage systems |
|
|
|
|
|
|
|
|
|
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<localSessionStorage> parameter |
|
|
|
|
(completed with C<localSessionStorageOptions>) and used to share authenticated users |
|
|
|
|
between Apache's threads or processus and of course between virtual hosts, |
|
|
|
|
|
|
|
|
|
=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. |
|
|
|
|
|
|
|
|
|
=back |
|
|
|
|
|
|
|
|
|
So the number of request to the central storage is limited to 1 per active |
|
|
|
|
user each 10 minutes. |
|
|
|
|
|
|
|
|
|
Lemonldap::NG is very fast, but you can increase performance using a |
|
|
|
|
L<Cache::Cache> module that does not use disk access. |
|
|
|
|
|
|
|
|
|
=head2 Logout system |
|
|
|
|
|
|
|
|
|
Lemonldap::NG provides a single logout system: you can use it by adding a link |
|
|
|
|
to the portal with "logout=1" parameter in the portal (See |
|
|
|
|
L<Lemonldap::NG::Portal>) and/or by configuring handler to intercept some URL |
|
|
|
|
(See Sinopsys). The logout system: |
|
|
|
|
|
|
|
|
|
=over |
|
|
|
|
|
|
|
|
|
=item * delete session in the global session storage, |
|
|
|
|
|
|
|
|
|
=item * replace Lemonldap::NG cookie by '', |
|
|
|
|
|
|
|
|
|
=item * delete handler caches only if logout action was started from a |
|
|
|
|
protected application and only in the current Apache server. So in other |
|
|
|
|
servers, session is still in cache for 10 minutes maximum if the user was |
|
|
|
|
connected on it in the last 10 minutes. |
|
|
|
|
|
|
|
|
|
=back |
|
|
|
|
|
|
|
|
|
You can also configure rules in the Manager interface to intercept logout URL. |
|
|
|
|
See L<Lemonldap::NG::Manager> and L<Lemonldap::NG::Handler> for more. |
|
|
|
|
|
|
|
|
|
=head1 USING LEMONLDAP::NG::HANDLER FOR DEVELOPMENT |
|
|
|
|
|
|
|
|
|
Lemonldap::NG::Handler provides different modules: |
|
|
|
|
|
|
|
|
|
=over |
|
|
|
|
|
|
|
|
|
=item * L<Lemonldap::NG::Handler::CGI>: if you have only a few Perl CGI to |
|
|
|
|
protect, you can use this module in your CGI instead of protecting it under |
|
|
|
|
L<Lemonldap::NG::Handler::ApacheMP2>. |
|
|
|
|
|
|
|
|
|
=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 |
|
|
|
|
|
|
|
|
|
L<Lemonldap::NG::Handler::DefaultHandler>, |
|
|
|
|
L<Lemonldap::NG::Portal>, L<Lemonldap::NG::Manager>, |
|
|
|
|
L<http://lemonldap-ng.org/> |
|
|
|
|
|
|
|
|
|
=head1 AUTHOR |
|
|
|
|
|
|
|
|
|
=over |
|
|
|
|
|
|
|
|
|
=item Clement Oudot, E<lt>clem.oudot@gmail.comE<gt> |
|
|
|
|
|
|
|
|
|
=item François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt> |
|
|
|
|
|
|
|
|
|
=item Xavier Guimard, E<lt>x.guimard@free.frE<gt> |
|
|
|
|
|
|
|
|
|
=back |
|
|
|
|
|
|
|
|
|
=head1 BUG REPORT |
|
|
|
|
|
|
|
|
|
Use OW2 system to report bug or ask for features: |
|
|
|
|
L<http://jira.ow2.org> |
|
|
|
|
|
|
|
|
|
=head1 DOWNLOAD |
|
|
|
|
|
|
|
|
|
Lemonldap::NG is available at |
|
|
|
|
L<http://forge.objectweb.org/project/showfiles.php?group_id=274> |
|
|
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
|
|
|
|
|
|
|
|
=over |
|
|
|
|
|
|
|
|
|
=item Copyright (C) 2005-2012 by Xavier Guimard, E<lt>x.guimard@free.frE<gt> |
|
|
|
|
|
|
|
|
|
=item Copyright (C) 2012-2015 by François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt> |
|
|
|
|
|
|
|
|
|
=item Copyright (C) 2006-2012 by Clement Oudot, E<lt>clem.oudot@gmail.comE<gt> |
|
|
|
|
|
|
|
|
|
=back |
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
|
|
|
|
it under the terms of the GNU General Public License as published by |
|
|
|
|
the Free Software Foundation; either version 2, or (at your option) |
|
|
|
|
any later version. |
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
|
|
GNU General Public License for more details. |
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License |
|
|
|
|
along with this program. If not, see L<http://www.gnu.org/licenses/>. |
|
|
|
|
|
|
|
|
|
=cut |
|
|
|
|