LEMONLDAP::NG : New auth architecture in Portal
This commit is contained in:
parent
f393d06a3d
commit
aca6815c1b
|
@ -2,9 +2,10 @@ lemonldap-ng (0.9.2) unstable; urgency=low
|
|||
|
||||
* New css in manager
|
||||
* cleaning Handler code
|
||||
* Status system for Lemonldap::NG::Handler
|
||||
* Status system for Lemonldap::NG::Handler and for the portal
|
||||
* Debian Czech translation for debconf (Closes: #483301 / bugs.debian.org)
|
||||
|
||||
-- Xavier Guimard <x.guimard@free.fr> Fri, 09 May 2008 22:10:37 +0200
|
||||
-- Xavier Guimard <x.guimard@free.fr> Wed, 28 May 2008 10:53:28 +0200
|
||||
|
||||
lemonldap-ng (0.9.1) unstable; urgency=low
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ t/99-pod.t
|
|||
t/Lemonldap-NG-Portal-AuthApache.t
|
||||
t/Lemonldap-NG-Portal-AuthCAS.t
|
||||
t/Lemonldap-NG-Portal-AuthLA.t
|
||||
t/Lemonldap-NG-Portal-AuthLDAP.t
|
||||
t/Lemonldap-NG-Portal-AuthSSL.t
|
||||
t/Lemonldap-NG-Portal-CDA.t
|
||||
t/Lemonldap-NG-Portal-i18n.t
|
||||
|
|
|
@ -2,26 +2,26 @@ package Lemonldap::NG::Portal::AuthApache;
|
|||
|
||||
use strict;
|
||||
use Lemonldap::NG::Portal::Simple;
|
||||
our @ISA = qw(Lemonldap::NG::Portal::Simple);
|
||||
|
||||
our $VERSION = '0.01';
|
||||
our $VERSION = '0.02';
|
||||
|
||||
our $OVERRIDE = {
|
||||
# By default, authentication is valid if REMOTE_USER environment
|
||||
# variable is present. Change formateFilter if this does not match with
|
||||
# UID.
|
||||
extractFormInfo => sub {
|
||||
my $self = shift;
|
||||
return PE_FORMEMPTY unless( $self->{user} = $ENV{REMOTE_USER} );
|
||||
# This is needed for Kerberos authentication
|
||||
$self->{user} =~ s/(.*)@(.*)/$1/g;
|
||||
PE_OK;
|
||||
},
|
||||
# By default, authentication is valid if REMOTE_USER environment
|
||||
# variable is present. Change formateFilter if this does not match with
|
||||
# UID.
|
||||
sub extractFormInfo {
|
||||
my $self = shift;
|
||||
return PE_FORMEMPTY unless ( $self->{user} = $ENV{REMOTE_USER} );
|
||||
|
||||
# Authentication is made by Apache.
|
||||
authenticate => sub {
|
||||
PE_OK;
|
||||
},
|
||||
};
|
||||
# This is needed for Kerberos authentication
|
||||
$self->{user} =~ s/(.*)@(.*)/$1/g;
|
||||
PE_OK;
|
||||
}
|
||||
|
||||
# Authentication is made by Apache.
|
||||
sub authenticate {
|
||||
PE_OK;
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
|
|
@ -2,12 +2,12 @@ package Lemonldap::NG::Portal::AuthCAS;
|
|||
|
||||
use strict;
|
||||
use Lemonldap::NG::Portal::Simple;
|
||||
our @ISA = qw(Lemonldap::NG::Portal::Simple);
|
||||
use AuthCAS;
|
||||
|
||||
our $VERSION = '0.02';
|
||||
our $VERSION = '0.03';
|
||||
|
||||
our $OVERRIDE = {
|
||||
extractFormInfo => sub {
|
||||
sub extractFormInfo {
|
||||
my $self = shift;
|
||||
my $cas = new AuthCAS(casUrl => $self->{CAS_url},
|
||||
CAFile => $self->{CAS_CAFile},
|
||||
|
@ -24,12 +24,11 @@ our $OVERRIDE = {
|
|||
exit;
|
||||
}
|
||||
PE_OK;
|
||||
},
|
||||
}
|
||||
|
||||
authenticate => sub {
|
||||
sub authenticate {
|
||||
PE_OK;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package Lemonldap::NG::Portal::AuthLDAP;
|
||||
|
||||
use strict;
|
||||
use Lemonldap::NG::Portal::Simple;
|
||||
|
||||
our @ISA = qw(Lemonldap::NG::Portal::Simple);
|
||||
|
||||
our $VERSION = '0.1';
|
||||
|
||||
sub extractFormInfo {
|
||||
my $self = shift;
|
||||
return PE_FIRSTACCESS
|
||||
unless ( $self->param('user') );
|
||||
return PE_FORMEMPTY
|
||||
unless ( length( $self->{'user'} = $self->param('user') ) > 0
|
||||
&& length( $self->{'password'} = $self->param('password') ) > 0 );
|
||||
PE_OK;
|
||||
}
|
||||
|
||||
sub authenticate {
|
||||
my $self = shift;
|
||||
$self->unbind();
|
||||
my $err;
|
||||
return $err unless ( ( $err = $self->connectLDAP ) == PE_OK );
|
||||
|
||||
# Check if we use Ppolicy control
|
||||
if ( $self->{ldapPpolicyControl} ) {
|
||||
|
||||
# require Perl module
|
||||
eval 'require Net::LDAP::Control::PasswordPolicy';
|
||||
die('Module Net::LDAP::Control::PasswordPolicy not found in @INC')
|
||||
if ($@);
|
||||
eval
|
||||
'use Net::LDAP::Constant qw( LDAP_CONTROL_PASSWORDPOLICY LDAP_PP_ACCOUNT_LOCKED LDAP_PP_PASSWORD_EXPIRED );';
|
||||
no strict 'subs';
|
||||
|
||||
# Create Control object
|
||||
my $pp = Net::LDAP::Control::PasswordPolicy->new;
|
||||
|
||||
# Bind with user credentials
|
||||
my $mesg = $self->{ldap}->bind(
|
||||
$self->{dn},
|
||||
password => $self->{password},
|
||||
control => [$pp]
|
||||
);
|
||||
|
||||
# Get bind response
|
||||
return PE_OK if ( $mesg->code == 0 );
|
||||
|
||||
# Get server control response
|
||||
my ($resp) = $mesg->control(LDAP_CONTROL_PASSWORDPOLICY);
|
||||
|
||||
if ( defined $resp ) {
|
||||
my $pp_error = $resp->error;
|
||||
if ($pp_error) {
|
||||
return PE_PP_ACCOUNT_LOCKED
|
||||
if ( $pp_error == LDAP_PP_ACCOUNT_LOCKED );
|
||||
return PE_PP_PASSWORD_EXPIRED
|
||||
if ( $pp_error == LDAP_PP_PASSWORD_EXPIRED );
|
||||
}
|
||||
else {
|
||||
return PE_BADCREDENTIALS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return PE_LDAPERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return PE_BADCREDENTIALS
|
||||
unless (
|
||||
$self->_bind( $self->{ldap}, $self->{dn}, $self->{password} ) );
|
||||
}
|
||||
$self->{sessionInfo}->{authenticationLevel} = 2;
|
||||
PE_OK;
|
||||
}
|
||||
1;
|
|
@ -2,6 +2,9 @@ package Lemonldap::NG::Portal::AuthSSL;
|
|||
|
||||
use strict;
|
||||
use Lemonldap::NG::Portal::Simple;
|
||||
use Lemonldap::NG::Portal::AuthLDAP;
|
||||
|
||||
our @ISA = qw(Lemonldap::NG::Portal::AuthLDAP Lemonldap::NG::Portal::Simple);
|
||||
|
||||
our $VERSION = '0.1';
|
||||
|
||||
|
@ -9,70 +12,71 @@ our $VERSION = '0.1';
|
|||
# Directory.
|
||||
# So authenticate is overloaded to return only PE_OK.
|
||||
|
||||
our $OVERRIDE = {
|
||||
# By default, authentication is valid if SSL_CLIENT_S_DN_Email environment
|
||||
# variable is present. Adapt it if you want
|
||||
sub extractFormInfo {
|
||||
my $self = shift;
|
||||
|
||||
# By default, authentication is valid if SSL_CLIENT_S_DN_Email environment
|
||||
# variable is present. Adapt it if you want
|
||||
extractFormInfo => sub {
|
||||
my $self = shift;
|
||||
# Defaults values
|
||||
$self->{SSLRequire} = 1 unless ( defined $self->{SSLRequire} );
|
||||
$self->{SSLVar} ||= 'SSL_CLIENT_S_DN_Email';
|
||||
$self->{SSLLDAPField} ||= 'mail';
|
||||
|
||||
# Defaults values
|
||||
$self->{SSLRequire} = 1 unless ( defined $self->{SSLRequire} );
|
||||
$self->{SSLVar} ||= 'SSL_CLIENT_S_DN_Email';
|
||||
$self->{SSLLDAPField} ||= 'mail';
|
||||
my $user = $self->https ? $ENV{ $self->{SSLVar} } : 0;
|
||||
if ($user) {
|
||||
$self->{sessionInfo}->{authenticationLevel} = 5;
|
||||
$self->{user} = $user;
|
||||
return PE_OK;
|
||||
}
|
||||
elsif ( $self->{SSLRequire} ) {
|
||||
return PE_CERTIFICATEREQUIRED;
|
||||
}
|
||||
return $self->SUPER::extractFormInfo(@_);
|
||||
}
|
||||
|
||||
my $user = $self->https ? $ENV{$self->{SSLVar}} : 0;
|
||||
if ($user) {
|
||||
$self->{sessionInfo}->{authenticationLevel} = 5;
|
||||
$self->{user} = $user;
|
||||
return PE_OK;
|
||||
}
|
||||
elsif ( $self->{SSLRequire} ) {
|
||||
return PE_CERTIFICATEREQUIRED;
|
||||
}
|
||||
return $self->extractFormInfo(@_);
|
||||
},
|
||||
# As we know only user mail (or SSLVar), we have to use it to find him in
|
||||
# the LDAP directory
|
||||
sub formateFilter {
|
||||
my $self = shift;
|
||||
if ( $self->{sessionInfo}->{authenticationLevel}
|
||||
and $self->{sessionInfo}->{authenticationLevel} > 4 )
|
||||
{
|
||||
$self->{filter} = '(&('
|
||||
. $self->{SSLLDAPField} . '='
|
||||
. $self->{user}
|
||||
. ")(objectClass=person))";
|
||||
return PE_OK;
|
||||
}
|
||||
return $self->SUPER::formateFilter(@_);
|
||||
}
|
||||
|
||||
# As we know only user mail (or SSLVar), we have to use it to find him in
|
||||
# the LDAP directory
|
||||
formateFilter => sub {
|
||||
my $self = shift;
|
||||
if ( $self->{sessionInfo}->{authenticationLevel} and $self->{sessionInfo}->{authenticationLevel} > 4 ) {
|
||||
$self->{filter} = '(&('
|
||||
. $self->{SSLLDAPField} . '='
|
||||
. $self->{user}
|
||||
. ")(objectClass=person))";
|
||||
return PE_OK;
|
||||
}
|
||||
return $self->formateFilter(@_);
|
||||
},
|
||||
|
||||
# Apache SSL environment variable are available in exportedVars:
|
||||
setSessionInfo => sub {
|
||||
my $self = shift;
|
||||
my $save = $self->{exportedVars};
|
||||
if ( ref( $self->{exportedVars} ) eq 'HASH' ) {
|
||||
foreach ( keys %{ $self->{exportedVars} } ) {
|
||||
if (/^SSL/) {
|
||||
$self->{sessionInfo}->{$_} = $ENV{$_};
|
||||
delete $self->{exportedVars}->{$_};
|
||||
}
|
||||
# Apache SSL environment variable are available in exportedVars:
|
||||
sub setSessionInfo {
|
||||
my $self = shift;
|
||||
my $save = $self->{exportedVars};
|
||||
if ( ref( $self->{exportedVars} ) eq 'HASH' ) {
|
||||
foreach ( keys %{ $self->{exportedVars} } ) {
|
||||
if (/^SSL/) {
|
||||
$self->{sessionInfo}->{$_} = $ENV{$_};
|
||||
delete $self->{exportedVars}->{$_};
|
||||
}
|
||||
}
|
||||
my $r = $self->setSessionInfo(@_);
|
||||
$self->{exportedVars} = $save;
|
||||
return $r;
|
||||
},
|
||||
}
|
||||
my $r = $self->SUPER::setSessionInfo(@_);
|
||||
$self->{exportedVars} = $save;
|
||||
return $r;
|
||||
}
|
||||
|
||||
# If authentication has been done with SSL, LDAP bind is disabled
|
||||
authenticate => sub {
|
||||
my $self = shift;
|
||||
if ( $self->{sessionInfo}->{authenticationLevel} and $self->{sessionInfo}->{authenticationLevel} > 4 ) {
|
||||
return PE_OK;
|
||||
}
|
||||
return $self->authenticate(@_);
|
||||
},
|
||||
};
|
||||
# If authentication has been done with SSL, LDAP bind is disabled
|
||||
sub authenticate {
|
||||
my $self = shift;
|
||||
if ( $self->{sessionInfo}->{authenticationLevel}
|
||||
and $self->{sessionInfo}->{authenticationLevel} > 4 )
|
||||
{
|
||||
return PE_OK;
|
||||
}
|
||||
return $self->SUPER::authenticate(@_);
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
|
|
@ -61,21 +61,14 @@ sub new {
|
|||
$self->{securedCookie} ||= 0;
|
||||
$self->{cookieName} ||= "lemonldap";
|
||||
$self->{ldapPpolicyControl} ||= 0;
|
||||
$self->{authentication} ||= 'LDAP';
|
||||
$self->{authentication} =~ s/^ldap/LDAP/;
|
||||
|
||||
if ( $self->{authentication} and $self->{authentication} ne "ldap" ) {
|
||||
|
||||
# $Lemonldap::NG::Portal::AuthSSL::OVERRIDE does not overload $self
|
||||
# variables: if the administrator has defined a sub, we respect it
|
||||
my $tmp =
|
||||
'require Lemonldap::NG::Portal::Auth'
|
||||
. $self->{authentication}
|
||||
. '; $tmp = $Lemonldap::NG::Portal::Auth'
|
||||
. $self->{authentication}
|
||||
. '::OVERRIDE;';
|
||||
eval $tmp;
|
||||
die($@) if ($@);
|
||||
%$self = ( %$tmp, %$self );
|
||||
}
|
||||
# $Lemonldap::NG::Portal::AuthSSL::OVERRIDE does not overload $self
|
||||
# variables: if the administrator has defined a sub, we respect it
|
||||
eval 'require Lemonldap::NG::Portal::Auth' . $self->{authentication};
|
||||
die($@) if ($@);
|
||||
bless $self, 'Lemonldap::NG::Portal::Auth' . $self->{authentication};
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
@ -103,6 +96,7 @@ sub error {
|
|||
# Private sub used to bind to LDAP server both with Lemonldap::NG account and user
|
||||
# credentials if LDAP authentication is used
|
||||
sub _bind {
|
||||
my $self = shift;
|
||||
my ( $ldap, $dn, $password ) = @_;
|
||||
my $mesg;
|
||||
if ( $dn and $password ) { # named bind
|
||||
|
@ -270,15 +264,8 @@ sub existingSession {
|
|||
|
||||
# 3. In ldap authentication scheme, we load here user and password from HTML
|
||||
# form
|
||||
sub extractFormInfo {
|
||||
my $self = shift;
|
||||
return PE_FIRSTACCESS
|
||||
unless ( $self->param('user') );
|
||||
return PE_FORMEMPTY
|
||||
unless ( length( $self->{'user'} = $self->param('user') ) > 0
|
||||
&& length( $self->{'password'} = $self->param('password') ) > 0 );
|
||||
PE_OK;
|
||||
}
|
||||
|
||||
# sub extractFormInfo has to be defined in Auth module used
|
||||
|
||||
# Unused. You can overload if you have to modify user and password before
|
||||
# authentication
|
||||
|
@ -290,7 +277,7 @@ sub formateParams() {
|
|||
# it with Active Directory, overload it to use CN instead of UID.
|
||||
sub formateFilter {
|
||||
my $self = shift;
|
||||
$self->{filter} = "(&(uid=" . $self->{user} . ")(objectClass=person))";
|
||||
$self->{filter} = "(&(uid=" . $self->{user} . ")(objectClass=inetOrgPerson))";
|
||||
PE_OK;
|
||||
}
|
||||
|
||||
|
@ -333,7 +320,7 @@ sub bind {
|
|||
$self->connectLDAP unless ( $self->{ldap} );
|
||||
return PE_WRONGMANAGERACCOUNT
|
||||
unless (
|
||||
&_bind( $self->{ldap}, $self->{managerDn}, $self->{managerPassword} ) );
|
||||
$self->_bind( $self->{ldap}, $self->{managerDn}, $self->{managerPassword} ) );
|
||||
PE_OK;
|
||||
}
|
||||
|
||||
|
@ -404,62 +391,8 @@ sub unbind {
|
|||
}
|
||||
|
||||
# 12. Default authentication: LDAP bind with user credentials
|
||||
sub authenticate {
|
||||
my $self = shift;
|
||||
$self->unbind();
|
||||
my $err;
|
||||
return $err unless ( ( $err = $self->connectLDAP ) == PE_OK );
|
||||
|
||||
# Check if we use Ppolicy control
|
||||
if ( $self->{ldapPpolicyControl} ) {
|
||||
|
||||
# require Perl module
|
||||
eval 'require Net::LDAP::Control::PasswordPolicy';
|
||||
die('Module Net::LDAP::Control::PasswordPolicy not found in @INC')
|
||||
if ($@);
|
||||
eval
|
||||
'use Net::LDAP::Constant qw( LDAP_CONTROL_PASSWORDPOLICY LDAP_PP_ACCOUNT_LOCKED LDAP_PP_PASSWORD_EXPIRED );';
|
||||
no strict 'subs';
|
||||
|
||||
# Create Control object
|
||||
my $pp = Net::LDAP::Control::PasswordPolicy->new;
|
||||
|
||||
# Bind with user credentials
|
||||
my $mesg = $self->{ldap}->bind(
|
||||
$self->{dn},
|
||||
password => $self->{password},
|
||||
control => [$pp]
|
||||
);
|
||||
|
||||
# Get bind response
|
||||
return PE_OK if ( $mesg->code == 0 );
|
||||
|
||||
# Get server control response
|
||||
my ($resp) = $mesg->control(LDAP_CONTROL_PASSWORDPOLICY);
|
||||
|
||||
if ( defined $resp ) {
|
||||
my $pp_error = $resp->error;
|
||||
if ($pp_error) {
|
||||
return PE_PP_ACCOUNT_LOCKED
|
||||
if ( $pp_error == LDAP_PP_ACCOUNT_LOCKED );
|
||||
return PE_PP_PASSWORD_EXPIRED
|
||||
if ( $pp_error == LDAP_PP_PASSWORD_EXPIRED );
|
||||
}
|
||||
else {
|
||||
return PE_BADCREDENTIALS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return PE_LDAPERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return PE_BADCREDENTIALS
|
||||
unless ( &_bind( $self->{ldap}, $self->{dn}, $self->{password} ) );
|
||||
}
|
||||
$self->{sessionInfo}->{authenticationLevel} = 2;
|
||||
PE_OK;
|
||||
}
|
||||
# sub authenticate has to be defined in Auth module used
|
||||
|
||||
# 13. Now, the user is authenticated. It's time to store his parameters with
|
||||
# Apache::Session::* module
|
||||
|
@ -696,7 +629,7 @@ Does nothing. To be overloaded if needed.
|
|||
|
||||
Creates the ldap filter using $self->{user}. By default :
|
||||
|
||||
$self->{filter} = "(&(uid=" . $self->{user} . ")(objectClass=person))";
|
||||
$self->{filter} = "(&(uid=" . $self->{user} . ")(objectClass=inetOrgPerson))";
|
||||
|
||||
=head3 connectLDAP
|
||||
|
||||
|
@ -761,7 +694,7 @@ described above
|
|||
|
||||
=head3 _bind( $ldap, $dn, $password )
|
||||
|
||||
Non-object method used to bind to the ldap server.
|
||||
Method used to bind to the ldap server.
|
||||
|
||||
=head3 header
|
||||
|
||||
|
|
Loading…
Reference in New Issue