152 lines
4.5 KiB
Perl
152 lines
4.5 KiB
Perl
# Auth::AD inherits from Auth::LDAP. It defines some additional configuration
|
|
# parameters and manage AD password expiration
|
|
|
|
package Lemonldap::NG::Portal::Auth::AD;
|
|
|
|
use strict;
|
|
use Mouse;
|
|
use Lemonldap::NG::Portal::Main::Constants
|
|
qw(PE_OK PE_PP_PASSWORD_EXPIRED PE_PP_CHANGE_AFTER_RESET);
|
|
|
|
our $VERSION = '2.0.2';
|
|
|
|
extends 'Lemonldap::NG::Portal::Auth::LDAP';
|
|
|
|
# PROPERTIES
|
|
|
|
has adPwdMaxAge => (
|
|
is => 'rw',
|
|
lazy => 1,
|
|
builder => sub {
|
|
my $conf = $_[0]->{conf};
|
|
my $res = $conf->{ADPwdMaxAge} || 0;
|
|
return $res * 10000000; # padding with '0' to obtain 0.1 micro-seconds
|
|
}
|
|
);
|
|
|
|
has adPwdExpireWarning => (
|
|
is => 'rw',
|
|
lazy => 1,
|
|
builder => sub {
|
|
my $conf = $_[0]->{conf};
|
|
my $res = $conf->{ADPwdExpireWarning} || 0;
|
|
return $res * 10000000; # padding with '0' to obtain 0.1 micro-seconds
|
|
}
|
|
);
|
|
|
|
# AD timestamp starts from Jan 01 1601 and is defined in 0.1 micro seconds.
|
|
# This method converts Unix timestamp into AD timestamp.
|
|
sub adTime {
|
|
return ( time + 11644473600 ) * 10000000;
|
|
}
|
|
|
|
# INITIALIZATION
|
|
# update LDAP configuration
|
|
sub init {
|
|
my ($self) = @_;
|
|
|
|
$self->conf->{ldapExportedVars}->{_AD_pwdLastSet} = 'pwdLastSet';
|
|
$self->conf->{ldapExportedVars}->{_AD_userAccountControl} =
|
|
'userAccountControl';
|
|
$self->conf->{ldapExportedVars}->{_AD_msDS_UACC} =
|
|
'msDS-User-Account-Control-Computed';
|
|
|
|
if ( $self->adPwdExpireWarning > $self->adPwdMaxAge ) {
|
|
$self->adPwdExpireWarning( $self->adPwdMaxAge );
|
|
$self->logger->warn(
|
|
"Error: ADPwdExpireWarning > ADPwdMaxAge, this should not happen",
|
|
);
|
|
}
|
|
return $self->SUPER::init();
|
|
}
|
|
|
|
# RUNNING METHODS
|
|
|
|
sub authenticate {
|
|
my ( $self, $req ) = @_;
|
|
my $res = $self->SUPER::authenticate($req);
|
|
|
|
my $pls = $self->ldap->getLdapValue( $req->data->{entry}, 'pwdLastSet' );
|
|
my $computed = $self->ldap->getLdapValue( $req->data->{entry},
|
|
'msDS-User-Account-Control-Computed' );
|
|
my $_adUac =
|
|
$self->ldap->getLdapValue( $req->data->{entry}, 'userAccountControl' )
|
|
|| 0;
|
|
|
|
unless ( $res == PE_OK ) {
|
|
|
|
# Check specific AD attributes
|
|
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->userLogger->warn("[AD] Password has expired");
|
|
$res = PE_PP_PASSWORD_EXPIRED;
|
|
}
|
|
|
|
# Password must be changed if pwdLastSet 0
|
|
if ( defined $pls and $pls == 0 ) {
|
|
$self->userLogger->warn(
|
|
"[AD] Password reset. User must change his password");
|
|
$res = PE_PP_CHANGE_AFTER_RESET;
|
|
}
|
|
|
|
}
|
|
else {
|
|
my $timestamp = $self->adTime;
|
|
|
|
# Compute password expiration time (date)
|
|
my $_pwdExpire = $pls || $timestamp;
|
|
$_pwdExpire += $self->adPwdMaxAge;
|
|
|
|
# computing when the warning message is displayed on portal
|
|
# (date - delay = date)
|
|
my $_pwdWarning = $_pwdExpire - $self->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;
|
|
$req->info(
|
|
$self->loadTemplate(
|
|
$req,
|
|
'pwdWillExpire',
|
|
params => {
|
|
time => join(
|
|
',',
|
|
$self->ldap->convertSec(
|
|
substr(
|
|
$remainingTime, 0,
|
|
length($remainingTime) - 7
|
|
)
|
|
)
|
|
)
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
# Remember password if password reset needed
|
|
if (
|
|
$res == PE_PP_CHANGE_AFTER_RESET
|
|
or ( $res == PE_PP_PASSWORD_EXPIRED
|
|
and $self->conf->{ldapAllowResetExpiredPassword} )
|
|
)
|
|
{
|
|
$req->data->{oldpassword} = $self->{password};
|
|
$req->data->{noerror} = 1;
|
|
$self->setSecurity($req);
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
1;
|