purgeFailureTimes( policyConfig, pwdFailTimeAt );
}
String failureTime = DateUtils.getGeneralizedTime();
pwdFailTimeAt.add( failureTime );
Modification pwdFailTimeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdFailTimeAt );
List<Modification> mods = new ArrayList<Modification>();
mods.add( pwdFailTimeMod );
int numFailures = pwdFailTimeAt.size();
if ( policyConfig.isPwdLockout() && ( numFailures >= policyConfig.getPwdMaxFailure() ) )
{
// Checking that we're not locking the admin user of the system partition
// See DIRSERVER-1812 (The default admin account should never get locked forever)
if ( !userEntry.getDn().equals( new Dn( schemaManager, ServerDNConstants.ADMIN_SYSTEM_DN ) ) )
{
Attribute pwdAccountLockedTimeAt = new DefaultAttribute( AT_PWD_ACCOUNT_LOCKED_TIME );
// if zero, lockout permanently, only admin can unlock it
if ( policyConfig.getPwdLockoutDuration() == 0 )
{
pwdAccountLockedTimeAt.add( "000001010000Z" );
}
else
{
pwdAccountLockedTimeAt.add( failureTime );
}
Modification pwdAccountLockedMod = new DefaultModification( ADD_ATTRIBUTE,
pwdAccountLockedTimeAt );
mods.add( pwdAccountLockedMod );
pwdRespCtrl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.ACCOUNT_LOCKED );
}
}
else if ( policyConfig.getPwdMinDelay() > 0 )
{
int numDelay = numFailures * policyConfig.getPwdMinDelay();
int maxDelay = policyConfig.getPwdMaxDelay();
if ( numDelay > maxDelay )
{
numDelay = maxDelay;
}
try
{
Thread.sleep( numDelay * 1000L );
}
catch ( InterruptedException e )
{
LOG.warn(
"Interrupted while delaying to send the failed authentication response for the user {}",
dn, e );
}
}
if ( !mods.isEmpty() )
{
String csnVal = directoryService.getCSN().toString();
Modification csnMod = new DefaultModification( REPLACE_ATTRIBUTE, ENTRY_CSN_AT, csnVal );
mods.add( csnMod );
ModifyOperationContext bindModCtx = new ModifyOperationContext( adminSession );
bindModCtx.setDn( dn );
bindModCtx.setEntry( userEntry );
bindModCtx.setModItems( mods );
bindModCtx.setPushToEvtInterceptor( true );
directoryService.getPartitionNexus().modify( bindModCtx );
}
}
String upDn = ( dn == null ? "" : dn.getName() );
throw new LdapAuthenticationException( I18n.err( I18n.ERR_229, upDn ) );
}
else if ( policyConfig != null )
{
List<Modification> mods = new ArrayList<Modification>();
if ( policyConfig.getPwdMaxIdle() > 0 )
{
Attribute pwdLastSuccesTimeAt = new DefaultAttribute( AT_PWD_LAST_SUCCESS );
pwdLastSuccesTimeAt.add( DateUtils.getGeneralizedTime() );
Modification pwdLastSuccesTimeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdLastSuccesTimeAt );
mods.add( pwdLastSuccesTimeMod );
}
Attribute pwdFailTimeAt = userEntry.get( AT_PWD_FAILURE_TIME );
if ( pwdFailTimeAt != null )
{
Modification pwdFailTimeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdFailTimeAt );
mods.add( pwdFailTimeMod );
}
Attribute pwdAccLockedTimeAt = userEntry.get( AT_PWD_ACCOUNT_LOCKED_TIME );
if ( pwdAccLockedTimeAt != null )
{
Modification pwdAccLockedTimeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdAccLockedTimeAt );
mods.add( pwdAccLockedTimeMod );
}
// checking the expiration time *after* performing authentication, do we need to care about millisecond precision?
if ( ( policyConfig.getPwdMaxAge() > 0 ) && ( policyConfig.getPwdGraceAuthNLimit() > 0 ) )
{
Attribute pwdChangeTimeAttr = userEntry.get( AT_PWD_CHANGED_TIME );
if ( pwdChangeTimeAttr != null )
{
boolean expired = PasswordUtil.isPwdExpired( pwdChangeTimeAttr.getString(),
policyConfig.getPwdMaxAge() );
if ( expired )
{
Attribute pwdGraceUseAttr = userEntry.get( AT_PWD_GRACE_USE_TIME );
int numGraceAuth = 0;
if ( pwdGraceUseAttr != null )
{
numGraceAuth = policyConfig.getPwdGraceAuthNLimit() - ( pwdGraceUseAttr.size() + 1 );
}
else
{
pwdGraceUseAttr = new DefaultAttribute( AT_PWD_GRACE_USE_TIME );
numGraceAuth = policyConfig.getPwdGraceAuthNLimit() - 1;
}
pwdRespCtrl.getResponse().setGraceAuthNRemaining( numGraceAuth );
pwdGraceUseAttr.add( DateUtils.getGeneralizedTime() );
Modification pwdGraceUseMod = new DefaultModification( ADD_ATTRIBUTE, pwdGraceUseAttr );
mods.add( pwdGraceUseMod );
}
}
}
if ( !mods.isEmpty() )
{
String csnVal = directoryService.getCSN().toString();
Modification csnMod = new DefaultModification( REPLACE_ATTRIBUTE, ENTRY_CSN_AT, csnVal );
mods.add( csnMod );
ModifyOperationContext bindModCtx = new ModifyOperationContext( adminSession );
bindModCtx.setDn( dn );
bindModCtx.setEntry( userEntry );