519 lines
16 KiB
Perl
519 lines
16 KiB
Perl
## @file
|
|
# Alias for Lemonldap::NG::SharedConf
|
|
|
|
## @class
|
|
# Alias for Lemonldap::NG::SharedConf
|
|
package Lemonldap::NG::Portal;
|
|
|
|
our $VERSION = '0.89';
|
|
use Lemonldap::NG::Portal::SharedConf;
|
|
use base 'Lemonldap::NG::Portal::SharedConf';
|
|
|
|
1;
|
|
|
|
__END__
|
|
|
|
=pod
|
|
|
|
=head1 NAME
|
|
|
|
Lemonldap::NG::Portal - The authentication portal part of Lemonldap::NG Web-SSO
|
|
system.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use Lemonldap::NG::Portal::SharedConf;
|
|
my $portal = new Lemonldap::NG::Portal::SharedConf (
|
|
configStorage => {
|
|
type => 'DBI',
|
|
dbiChain => "dbi:mysql:database=lmSessions;host=1.2.3.4",
|
|
dbiUser => "lemon",
|
|
dbiPassword => "pass",
|
|
},
|
|
# Activate SOAP service
|
|
Soap => 1
|
|
);
|
|
|
|
|
|
if($portal->process()) {
|
|
# Write here the menu with CGI methods. This page is displayed ONLY IF
|
|
# the user was not redirected here by a Lemonldap::NG::Handler,
|
|
# else, the process sub redirect the user to the initial requested URI.
|
|
print $portal->header('text/html; charset=utf8'); # DON'T FORGET THIS (see L<CGI(3)>)
|
|
print "...";
|
|
|
|
# or redirect the user to the menu
|
|
print $portal->redirect( -uri => 'https://portal/menu');
|
|
|
|
# You can also add a "Logout" link:
|
|
print "<a href=\"$ENV{SCRIPT_NAME}?logout=1\">";
|
|
}
|
|
else {
|
|
# Write here the html form used to authenticate with CGI methods.
|
|
# $portal->error returns the error message if authentification failed
|
|
# You can force the language in error like this :
|
|
# print $portal->error('fr')
|
|
# Warning: by defaut, input names are "user" and "password"
|
|
print $portal->header('text/html; charset=utf8'); # DON'T FORGET THIS (see L<CGI(3)>)
|
|
print "<html> ...";
|
|
print '<form method="POST">';
|
|
# In your form, the following value is required for redirection
|
|
print '<input type="hidden" name="url" value="'.$portal->param('url').'">';
|
|
# Next, login and password
|
|
print 'Login : <input name="user"><br>';
|
|
print 'Password : <input name="password" type="password" autocomplete="off"><br>';
|
|
print '<input type=submit value="OK">';
|
|
print '</form>';
|
|
}
|
|
|
|
SOAP mode authentication (client) :
|
|
|
|
#!/usr/bin/perl -l
|
|
|
|
use SOAP::Lite;
|
|
use Data::Dumper;
|
|
|
|
my $soap =
|
|
SOAP::Lite->proxy('http://auth.example.com/')
|
|
->uri('urn:/Lemonldap::NG::Common::CGI::SOAPService');
|
|
my $r = $soap->getCookies( 'user', 'password' );
|
|
|
|
# Catch SOAP errors
|
|
if ( $r->fault ) {
|
|
print STDERR "SOAP Error: " . $r->fault->{faultstring};
|
|
}
|
|
else {
|
|
my $res = $r->result();
|
|
|
|
# If authentication failed, display error
|
|
if ( $res->{error} ) {
|
|
print STDERR "Error: " . $soap->error( 'fr', $res->{error} )->result();
|
|
}
|
|
|
|
# print session-ID
|
|
else {
|
|
print "Cookie: lemonldap=" . $res->{cookies}->{lemonldap};
|
|
}
|
|
}
|
|
|
|
=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 portal part inherits from L<CGI> so yo can use it both with Apache 1 and 2
|
|
and use all L<CGI> features.
|
|
|
|
=head2 Authentication, Autorization, Accounting
|
|
|
|
=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::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 if all your protected sites
|
|
use https.
|
|
|
|
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.
|
|
The purgeCentralCache provided in C<example/> directory can help you to do it.
|
|
By default, a session stay 10 minutes in the Handler 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),
|
|
|
|
=item * create Perl expression to define user groups (using ldap attributes):
|
|
optionnal, this mechanism is available with Lemonldap::NG::*::SharedConf
|
|
modules,
|
|
|
|
=item * create an array foreach virtual host associating URI regular
|
|
expressions and Perl expressions to use to grant access.
|
|
|
|
=back
|
|
|
|
=head4 Example
|
|
|
|
Exported variables (in Lemonldap::NG::Portal, will be stored in
|
|
configuration database):
|
|
|
|
exportedVars => {
|
|
cn => "cn",
|
|
departmentUID => "departmentUID",
|
|
login => "uid",
|
|
},
|
|
|
|
User groups (stored in configuration database with L<Lemonldap::NG::Manager>):
|
|
|
|
groups => {
|
|
group1 => '{ $departmentUID eq "unit1" or $login = "xavier.guimard" }',
|
|
...
|
|
},
|
|
|
|
Area protection (stored in configuration database with
|
|
L<Lemonldap::NG::Manager>):
|
|
|
|
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: see examples in
|
|
L<Lemonldap::NG::Portal> distribution) both in groups evaluations and area
|
|
protections (you just have to call them with a "$").
|
|
|
|
You have to be careful when choosing your expressions:
|
|
|
|
=over
|
|
|
|
=item * C<groups> are evaluated each time a user is redirected to the portal,
|
|
|
|
=item * C<locationRules> are evaluated for each request.
|
|
|
|
=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/',
|
|
},
|
|
},
|
|
|
|
You can also use ldap filters in C<groups> parameter, or Perl expression or
|
|
mixed expressions. 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 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
|
|
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<User-Auth> field is used but you can change
|
|
it using the C<exportedHeaders> parameters (stored in the configuration
|
|
database). This parameters contains an associative array:
|
|
|
|
=over
|
|
|
|
=item * B<keys> are the names of the choosen 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")',
|
|
},
|
|
}
|
|
|
|
=head2 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<globalglobalStorageOptions>) and used by
|
|
L<lemonldap::NG::Portal> to store authenticated user parameters,
|
|
|
|
=item * a L<Cache::Cache> module choosed with the C<localStorage> parameter
|
|
(completed with C<localStorageOptions> and used to share authenticated users
|
|
between Apache's threads or processus and of course between virtual hosts,
|
|
|
|
=item * Lemonldap::NG 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 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 (See Synopsis) and/or by configuring
|
|
Handler to intercept some URL directly in the manager interface and/or in
|
|
Apache configuration file (See L<Lemonldap::NG::Handler>). 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
|
|
|
|
=head2 Existing sessions
|
|
|
|
By default, when a user tries to connect to the portal with a valid cookie,
|
|
the portal proposes a new authentication. This behaviour can be change easily
|
|
by changing C<existingSession> sub :
|
|
|
|
use Lemonldap::NG::Portal::SharedConf qw(:all);
|
|
|
|
my $portal = Lemonldap::NG::Portal::SharedConf->new ( {
|
|
existingSession => sub {PE_DONE},
|
|
configStorage => ...
|
|
...
|
|
});
|
|
|
|
=head1 PORTAL OPTIONS
|
|
|
|
=head2 Manager options
|
|
|
|
All options here can be set both in the manager interface and in the
|
|
constructor ($portal->new()). Local arguments have the precedence on
|
|
arguments set by the manager.
|
|
|
|
=over
|
|
|
|
=item * ldapPort: tcp port used by ldap server.
|
|
|
|
=item * ldapBase: base of the ldap directory.
|
|
|
|
=item * managerDn: dn to used to connect to ldap server. By default, anonymous
|
|
bind is used.
|
|
|
|
=item * managerPassword: password to used to connect to ldap server. By
|
|
default, anonymous bind is used.
|
|
|
|
=item * securedCookie : set it to 1 if you want to protect user cookies.
|
|
|
|
=item * cookieName : name of the cookie used by Lemonldap::NG (lemonldap by
|
|
default).
|
|
|
|
=item * domain : cookie domain. You may have to give it else the SSO will work
|
|
only on your server.
|
|
|
|
=item * globalStorage : required: L<Apache::Session> library to used to store
|
|
session informations.
|
|
|
|
=item * globalStorageOptions : parameters to bind to L<Apache::Session> module
|
|
|
|
=item * locationRules : this parameter is used by L<Lemonldap::NG::Handler> to
|
|
read the rules. It can be set in the portal just to display protected sites by
|
|
the function C<getProtectedSites>.
|
|
|
|
=item * authentication: sheme to authenticate users (default: "ldap"). It can
|
|
be set to:
|
|
|
|
=over
|
|
|
|
=item * ldap : authentification is done by LDAP bind
|
|
|
|
=item * SSL : the portal reads SSL variables issued from Apache SSL
|
|
authentication. See L<Lemonldap::NG::Portal::AuthSSL> for more.
|
|
|
|
=item * CAS : use CAS system to authenticate users. See
|
|
L<Lemonldap::NG::Portal::AuthCAS> for more.
|
|
|
|
=item * Apache : the authentication is done by Apache configuration and the
|
|
portal reads the environment variable C<REMOTE_USER> to search the user in
|
|
the LDAP server. This can be used to authenticate users by Kerberos.
|
|
|
|
=item * LA : Liberty-Alliance mechanism. WARNING : at the moment, you have to
|
|
use directly L<Lemonldap::NG::Portal::AuthLA> because this target does not
|
|
work.
|
|
|
|
=back
|
|
|
|
=back
|
|
|
|
=head2 Local options
|
|
|
|
Those options can not be set using the manager but have to be passed to the
|
|
constructor (new()).
|
|
|
|
=over
|
|
|
|
=item * configStorage I<(required for Lemonldap::NG::Portal::SharedConf)> :
|
|
describe how to find configuration generated by L<Lemonldap::NG::Manager>. See
|
|
L<Lemonldap::NG::Common::Conf> for more
|
|
|
|
=item * caPath, caFile : if you use ldap+tls you can overwrite cafile or capath
|
|
options with those parameters. This is usefull if you use a shared
|
|
configuration.
|
|
|
|
=item * ldapPpolicyControl : set it to 1 if you want to use LDAP Password
|
|
Policy
|
|
|
|
=item * useLocalCachedConf : for each authentication, the portal process reads
|
|
its configuration. With a shared configuration stored on a network and if the
|
|
system has a heavy load and if you have a running L<Lemonldap::NG::Handler>
|
|
instance on the same server, you can used the configuration stored in the local
|
|
cache but setting this parameter to 1.
|
|
|
|
=item * localStorage, localStorageOptions : if the above option is set to 1, you
|
|
have to set the good values in those parameters. See L<Lemonldap::NG::Handler>
|
|
for the syntax.
|
|
|
|
=item * ldapGroupBase : this parameter can be used to store in the Lemonldap::NG
|
|
groups system all the LDAP groups that contains the user. Set here the LDAP base
|
|
of the LDAP groups. Example : C<"dmdName=groups,dc=example,dc=com">.
|
|
|
|
=item * I<methodName> : all method used by the process sub can be overloaded
|
|
simply using an option that referenced a sub. See
|
|
L<Lemonldap::NG::Portal::Simple> for more.
|
|
|
|
=back
|
|
|
|
CAS authentication options :
|
|
|
|
=over
|
|
|
|
=item * CAS_url, CAS_CAFile, CAS_loginUrl, CAS_validationUrl : see
|
|
L<Lemonldap::NG::Portal::AuthCAS> for more
|
|
|
|
=back
|
|
|
|
Liberty-Alliance authentication options :
|
|
|
|
=over
|
|
|
|
=item * laSp, laIdpsFile, laStorage, laLdapLoginAttribute, localStorage,
|
|
localStorageOptions, laDebug : see L<Lemonldap::NG::Portal::AuthLA> for more.
|
|
|
|
=back
|
|
|
|
SSL authentication options :
|
|
|
|
=over
|
|
|
|
=item * SSLRequire : if set to 0, both SSL and LDAP authentication are used.
|
|
If set to 1, client certificate are required.
|
|
|
|
=item * SSLVar : the name of the SSL variable to read. Default to
|
|
SSL_CLIENT_S_DN_Email.
|
|
|
|
=item * SSLLDAPField : the LDAP attribute that correspond to SSLVar.
|
|
|
|
=back
|
|
|
|
=head1 USING LEMONLDAP::NG::PORTAL FOR DEVELOPMENT
|
|
|
|
Lemonldap::NG::Portal provides different modules:
|
|
|
|
=over
|
|
|
|
=item * L<Lemonldap::NG::Portal::Simple>: base module to build a portal,
|
|
|
|
=item * L<Lemonldap::NG::Portal::Auth*>: authentication modules that modify
|
|
authentication scheme.
|
|
|
|
=item * L<Lemonldap::NG::Portal::AuthLA>: specific module to used
|
|
Liberty-Alliance mechanisms to authenticate users
|
|
|
|
=item * L<Lemonldap::NG::Portal::SharedConf>: this module provide the ability
|
|
to read portal configuration from a central database. It inherits from
|
|
L<Lemonldap::NG::Portal::Simple>. It's the more used module.
|
|
|
|
=back
|
|
|
|
=head1 SEE ALSO
|
|
|
|
L<Lemonldap::NG::Portal::SharedConf>, L<Lemonldap::NG::Portal::Simple>
|
|
L<Lemonldap::NG::Handler>, L<Lemonldap::NG::Manager>,
|
|
http://wiki.lemonldap.objectweb.org/xwiki/bin/view/NG/Presentation
|
|
|
|
=head1 AUTHOR
|
|
|
|
Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
|
|
|
=head1 BUG REPORT
|
|
|
|
Use OW2 system to report bug or ask for features:
|
|
L<http://forge.objectweb.org/tracker/?group_id=274>
|
|
|
|
=head1 DOWNLOAD
|
|
|
|
Lemonldap::NG is available at
|
|
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
|
|
|
Copyright (C) 2005-2007 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::NG 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
|