bindContext.setCredentials( null );
return;
}
boolean isPPolicyReqCtrlPresent = bindContext.hasRequestControl( PasswordPolicy.OID );
PasswordPolicyDecorator pwdRespCtrl =
new PasswordPolicyDecorator( directoryService.getLdapCodecService(), true );
boolean authenticated = false;
PasswordPolicyException ppe = null;
// TODO : we should refactor that.
// try each authenticator
for ( Authenticator authenticator : authenticators )
{
try
{
// perform the authentication
LdapPrincipal principal = authenticator.authenticate( bindContext );
LdapPrincipal clonedPrincipal = ( LdapPrincipal ) ( principal.clone() );
// remove creds so there is no security risk
bindContext.setCredentials( null );
clonedPrincipal.setUserPassword( StringConstants.EMPTY_BYTES );
// authentication was successful
CoreSession session = new DefaultCoreSession( clonedPrincipal, directoryService );
bindContext.setSession( session );
authenticated = true;
// break out of the loop if the authentication succeeded
break;
}
catch ( PasswordPolicyException e )
{
ppe = e;
break;
}
catch ( LdapAuthenticationException e )
{
// authentication failed, try the next authenticator
if ( LOG.isInfoEnabled() )
{
LOG.info( "Authenticator {} failed to authenticate: {}", authenticator, bindContext );
}
}
catch ( Exception e )
{
// Log other exceptions than LdapAuthenticationException
if ( LOG.isWarnEnabled() )
{
LOG.info( "Unexpected failure for Authenticator {} : {}", authenticator, bindContext );
}
}
}
if ( ppe != null )
{
if ( isPPolicyReqCtrlPresent )
{
pwdRespCtrl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.get( ppe.getErrorCode() ) );
bindContext.addResponseControl( pwdRespCtrl );
}
throw ppe;
}
Dn dn = bindContext.getDn();
Entry userEntry = bindContext.getEntry();
PasswordPolicyConfiguration policyConfig = getPwdPolicy( userEntry );
// check if the user entry is null, it will be null
// in cases of anonymous bind
if ( authenticated && ( userEntry == null ) && directoryService.isAllowAnonymousAccess() )
{
return;
}
if ( !authenticated )
{
if ( LOG.isInfoEnabled() )
{
LOG.info( "Cannot bind to the server " );
}
if ( ( policyConfig != null ) && ( userEntry != null ) )
{
Attribute pwdFailTimeAt = userEntry.get( PWD_FAILURE_TIME_AT );
if ( pwdFailTimeAt == null )
{
pwdFailTimeAt = new DefaultAttribute( AT_PWD_FAILURE_TIME );
}
else
{
PasswordUtil.purgeFailureTimes( policyConfig, pwdFailTimeAt );
}
String failureTime = DateUtils.getGeneralizedTime();
pwdFailTimeAt.add( failureTime );
Modification pwdFailTimeMod = new DefaultModification( ADD_ATTRIBUTE, pwdFailTimeAt );
List<Modification> mods = new ArrayList<Modification>();
mods.add( pwdFailTimeMod );
int numFailures = pwdFailTimeAt.size();
if ( policyConfig.isPwdLockout() && ( numFailures >= policyConfig.getPwdMaxFailure() ) )
{
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 * 1000 );
}
catch ( InterruptedException e )
{
LOG.warn(
"Interrupted while delaying to send the failed authentication response for the user {}",
dn, e );
}
}
//adminSession.modify( dn, Collections.singletonList( pwdFailTimeMod ) );
ModifyOperationContext bindModCtx = new ModifyOperationContext( adminSession );
bindModCtx.setByPassed( BYPASS_INTERCEPTORS );
bindModCtx.setDn( dn );
bindModCtx.setModItems( mods );
directoryService.getOperationManager().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( PWD_CHANGED_TIME_AT );
if ( pwdChangeTimeAttr != null )
{
boolean expired = PasswordUtil.isPwdExpired( pwdChangeTimeAttr.getString(),
policyConfig.getPwdMaxAge() );
if ( expired )
{
Attribute pwdGraceUseAttr = userEntry.get( PWD_GRACE_USE_TIME_AT );
if ( pwdGraceUseAttr != null )
{
pwdRespCtrl.getResponse().setGraceAuthNsRemaining( policyConfig.getPwdGraceAuthNLimit()
- ( pwdGraceUseAttr.size() + 1 ) );
}
else
{
pwdGraceUseAttr = new DefaultAttribute( AT_PWD_GRACE_USE_TIME );
}
pwdGraceUseAttr.add( DateUtils.getGeneralizedTime() );
Modification pwdGraceUseMod = new DefaultModification( ADD_ATTRIBUTE, pwdGraceUseAttr );
mods.add( pwdGraceUseMod );
}
}
}
if ( !mods.isEmpty() )
{
//adminSession.modify( dn, mods );
ModifyOperationContext bindModCtx = new ModifyOperationContext( adminSession );
bindModCtx.setByPassed( BYPASS_INTERCEPTORS );
bindModCtx.setDn( dn );
bindModCtx.setModItems( mods );
directoryService.getOperationManager().modify( bindModCtx );
}
if ( isPPolicyReqCtrlPresent )
{
int expiryWarnTime = getPwdTimeBeforeExpiry( userEntry, policyConfig );
if ( expiryWarnTime > 0 )
{
pwdRespCtrl.getResponse().setTimeBeforeExpiration( expiryWarnTime );
}
if ( isPwdMustReset( userEntry ) )
{
pwdRespCtrl.getResponse().setPasswordPolicyError( PasswordPolicyErrorEnum.CHANGE_AFTER_RESET );
pwdResetSet.add( dn );
}
bindContext.addResponseControl( pwdRespCtrl );
}