2013-04-28 16:44:03 +02:00
|
|
|
|
##@file
|
|
|
|
|
# AD authentication backend file
|
|
|
|
|
|
|
|
|
|
##@class
|
|
|
|
|
# AD authentication backend class
|
|
|
|
|
package Lemonldap::NG::Portal::AuthAD;
|
|
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
|
|
2015-10-05 16:07:24 +02:00
|
|
|
|
our $VERSION = '1.4.6';
|
2013-09-28 00:22:27 +02:00
|
|
|
|
use Lemonldap::NG::Portal::Simple;
|
2013-04-28 16:44:03 +02:00
|
|
|
|
use base qw(Lemonldap::NG::Portal::AuthLDAP);
|
|
|
|
|
|
|
|
|
|
*_formateFilter = *Lemonldap::NG::Portal::UserDBAD::formateFilter;
|
2013-09-30 10:38:24 +02:00
|
|
|
|
*getDisplayType = *Lemonldap::NG::Portal::AuthLDAP::getDisplayType;
|
2013-04-28 16:44:03 +02:00
|
|
|
|
|
2014-02-18 17:05:39 +01:00
|
|
|
|
## @apmethod int authInit()
|
2013-09-28 00:22:27 +02:00
|
|
|
|
# Add specific attributes for search
|
|
|
|
|
# @return Lemonldap::NG::Portal constant
|
|
|
|
|
sub authInit {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
|
2014-02-18 17:05:39 +01:00
|
|
|
|
$self->{ldapExportedVars}->{_AD_pwdLastSet} = 'pwdLastSet';
|
|
|
|
|
$self->{ldapExportedVars}->{_AD_userAccountControl} = 'userAccountControl';
|
2015-10-05 16:07:24 +02:00
|
|
|
|
$self->{ldapExportedVars}->{_AD_msDS_UACC} =
|
|
|
|
|
'msDS-User-Account-Control-Computed';
|
2013-09-28 00:22:27 +02:00
|
|
|
|
|
|
|
|
|
return $self->SUPER::authInit();
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-28 16:44:03 +02:00
|
|
|
|
## @apmethod int authenticate()
|
|
|
|
|
# Authenticate user by LDAP mechanism.
|
|
|
|
|
# Check AD specific attribute to get password state.
|
|
|
|
|
# @return Lemonldap::NG::Portal constant
|
|
|
|
|
sub authenticate {
|
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
|
|
my $res = $self->SUPER::authenticate;
|
|
|
|
|
|
2013-09-28 00:22:27 +02:00
|
|
|
|
unless ( $res == PE_OK ) {
|
|
|
|
|
|
|
|
|
|
# Check specific AD attributes
|
2015-10-06 11:39:23 +02:00
|
|
|
|
my $pls = $self->{sessionInfo}->{_AD_pwdLastSet};
|
2015-10-08 14:49:32 +02:00
|
|
|
|
my $computed = $self->{sessionInfo}->{_AD_msDS_UACC};
|
2015-10-05 16:07:24 +02:00
|
|
|
|
my $mask = 0xf00000; # mask to get the 8 at 6th position
|
|
|
|
|
my $expired_flag =
|
|
|
|
|
0x800000; # 8 at 6th position for flag UF_PASSWORD_EXPIRED to be set
|
|
|
|
|
if ( ( $computed & $mask ) == $expired_flag ) {
|
|
|
|
|
$self->lmLog( "[AD] Password has expired", 'warn' );
|
|
|
|
|
$res = PE_PP_PASSWORD_EXPIRED;
|
|
|
|
|
}
|
2013-09-28 00:22:27 +02:00
|
|
|
|
|
|
|
|
|
# Password must be changed if pwdLastSet 0
|
|
|
|
|
if ( $pls == 0 ) {
|
2015-10-05 16:07:24 +02:00
|
|
|
|
$self->lmLog( "[AD] Password reset. User must change his password",
|
|
|
|
|
'warn' );
|
2015-01-08 18:05:40 +01:00
|
|
|
|
$res = PE_PP_CHANGE_AFTER_RESET;
|
2013-09-28 00:22:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-06 11:39:23 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
|
|
# Getting password max age (delay)
|
|
|
|
|
my $ADPwdMaxAge = $self->{ADPwdMaxAge} || 0;
|
|
|
|
|
$ADPwdMaxAge *= 10000000; # padding with '0' to obtain 0.1 micro-seconds
|
|
|
|
|
|
|
|
|
|
# Getting password expiration warning time (delay)
|
|
|
|
|
my $ADPwdExpireWarning = $self->{ADPwdExpireWarning} || 0;
|
|
|
|
|
$ADPwdExpireWarning *=
|
|
|
|
|
10000000; # padding with '0' to obtain 0.1 micro-seconds
|
|
|
|
|
|
|
|
|
|
if ( $ADPwdExpireWarning > $ADPwdMaxAge ) {
|
|
|
|
|
$ADPwdExpireWarning = $ADPwdMaxAge;
|
|
|
|
|
$self->lmLog(
|
|
|
|
|
"Error: ADPwdExpireWarning > ADPwdMaxAge, this should not happen",
|
|
|
|
|
'warn'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# get userAccountControl to ckeck password expiration flags
|
|
|
|
|
my $_adUac = $self->{sessionInfo}->{_AD_userAccountControl} || 0;
|
|
|
|
|
|
|
|
|
|
# Compute current timestamp in AD format (date)
|
|
|
|
|
my $time = time; # unix timestamp (seconds since Jan 01 1970)
|
|
|
|
|
my $a_time =
|
|
|
|
|
$time + 11644473600; # adding difference (in s) from Jan 01 1601
|
|
|
|
|
my $timestamp =
|
|
|
|
|
$a_time . '0000000'; # padding with '0' to obatin 0.1 micro-seconds
|
|
|
|
|
|
|
|
|
|
# Compute password expiration time (date)
|
|
|
|
|
my $_pwdExpire = $self->{sessionInfo}->{_AD_pwdLastSet} || $timestamp;
|
|
|
|
|
$_pwdExpire += $ADPwdMaxAge;
|
|
|
|
|
|
|
|
|
|
# computing when the warning message is displayed on portal (date - delay = date)
|
|
|
|
|
my $_pwdWarning = $_pwdExpire - $ADPwdExpireWarning;
|
|
|
|
|
|
|
|
|
|
# display warning if account warning time before expiration is
|
|
|
|
|
# reached and flag "password nevers expires" is not set
|
|
|
|
|
if ( $timestamp > $_pwdWarning
|
|
|
|
|
&& $timestamp < $_pwdExpire
|
|
|
|
|
&& ( $_adUac & 0x10000 ) != 0x10000 )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
# calculating remaining time before password expiration
|
|
|
|
|
my $remainingTime = $_pwdExpire - $timestamp;
|
|
|
|
|
$self->info(
|
|
|
|
|
"<h3>"
|
|
|
|
|
. sprintf(
|
|
|
|
|
$self->msg(PM_PP_EXP_WARNING),
|
|
|
|
|
$self->convertSec(
|
|
|
|
|
substr( $remainingTime, 0, length($remainingTime) - 7 )
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
. "</h3>"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-28 00:22:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Remember password if password reset needed
|
|
|
|
|
$self->{oldpassword} = $self->{password}
|
|
|
|
|
if ( $res == PE_PP_CHANGE_AFTER_RESET );
|
2013-04-28 16:44:03 +02:00
|
|
|
|
|
|
|
|
|
return $res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
1;
|