private void processPasswordPolicydModify()

in interceptors/authn/src/main/java/org/apache/directory/server/core/authn/AuthenticationInterceptor.java [985:1147]


    private void processPasswordPolicydModify( ModifyOperationContext modifyContext ) throws LdapException
    {
        // handle the case where pwdPolicySubentry AT is about to be deleted in this modify()
        PasswordPolicyConfiguration policyConfig = getPwdPolicy( modifyContext.getEntry() );

        PwdModDetailsHolder pwdModDetails = getPwdModDetails( modifyContext, policyConfig );

        if ( !pwdModDetails.isPwdModPresent() )
        {
            // We can going on, the password attribute is not present in the Modifications.
            next( modifyContext );
        }
        else
        {
            // The password is present in the modifications. Deal with the various use cases.
            CoreSession userSession = modifyContext.getSession();
            boolean isPPolicyReqCtrlPresent = modifyContext.hasRequestControl( PasswordPolicyRequest.OID );
            
            // First, check if the password must be changed, and if the operation allows it
            checkPwdMustChange( modifyContext, userSession, pwdModDetails, isPPolicyReqCtrlPresent );

            // Check the the old password is present if it's required by the PP config
            checkOldPwdRequired( modifyContext, policyConfig, pwdModDetails, isPPolicyReqCtrlPresent );

            // Check that we can't update the password if it's not allowed
            checkChangePwdAllowed( modifyContext, policyConfig, isPPolicyReqCtrlPresent );

            Entry entry = modifyContext.getEntry();

            boolean removePwdReset = false;

            List<Modification> mods = new ArrayList<>();

            if ( pwdModDetails.isAddOrReplace() )
            {
                if ( isPwdTooYoung( modifyContext, entry, policyConfig ) )
                {
                    if ( isPPolicyReqCtrlPresent )
                    {
                        PasswordPolicyResponse responseControl = new PasswordPolicyResponseImpl();
                        responseControl.setPasswordPolicyError(
                            PasswordPolicyErrorEnum.PASSWORD_TOO_YOUNG );
                        modifyContext.addResponseControl( responseControl );
                    }

                    throw new LdapOperationException( ResultCodeEnum.CONSTRAINT_VIOLATION,
                        "password is too young to update" );
                }

                byte[] newPassword = pwdModDetails.getNewPwd();

                try
                {
                    check( modifyContext, entry, newPassword, policyConfig );
                }
                catch ( PasswordPolicyException e )
                {
                    if ( isPPolicyReqCtrlPresent )
                    {
                        PasswordPolicyResponse responseControl = new PasswordPolicyResponseImpl();
                        responseControl.setPasswordPolicyError(
                            PasswordPolicyErrorEnum.get( e.getErrorCode() ) );
                        modifyContext.addResponseControl( responseControl );
                    }

                    // throw exception if userPassword quality checks fail
                    throw new LdapOperationException( ResultCodeEnum.CONSTRAINT_VIOLATION, e.getMessage(), e );
                }

                int histSize = policyConfig.getPwdInHistory();
                Modification pwdRemHistMod = null;
                Modification pwdAddHistMod = null;
                String pwdChangedTime = DateUtils.getGeneralizedTime( directoryService.getTimeProvider() );

                if ( histSize > 0 )
                {
                    Attribute pwdHistoryAt = entry.get( pwdHistoryAT );

                    if ( pwdHistoryAt == null )
                    {
                        pwdHistoryAt = new DefaultAttribute( pwdHistoryAT );
                    }

                    // Build the Modification containing the password history
                    pwdRemHistMod = buildPwdHistory( modifyContext, pwdHistoryAt, histSize, 
                        newPassword, isPPolicyReqCtrlPresent );

                    PasswordHistory newPwdHist = new PasswordHistory( pwdChangedTime, newPassword );
                    pwdHistoryAt.add( newPwdHist.getHistoryValue() );
                    pwdAddHistMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdHistoryAt );
                }

                next( modifyContext );

                invalidateAuthenticatorCaches( modifyContext.getDn() );

                LookupOperationContext lookupContext = new LookupOperationContext( adminSession, modifyContext.getDn(),
                    SchemaConstants.ALL_ATTRIBUTES_ARRAY );
                lookupContext.setPartition( modifyContext.getPartition() );
                lookupContext.setTransaction( modifyContext.getTransaction() );
                
                entry = directoryService.getPartitionNexus().lookup( lookupContext );

                if ( ( policyConfig.getPwdMinAge() > 0 ) || ( policyConfig.getPwdMaxAge() > 0 ) )
                {
                    Attribute pwdChangedTimeAt = new DefaultAttribute( pwdChangedTimeAT );
                    pwdChangedTimeAt.add( pwdChangedTime );
                    Modification pwdChangedTimeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdChangedTimeAt );
                    mods.add( pwdChangedTimeMod );
                }

                if ( pwdAddHistMod != null )
                {
                    mods.add( pwdAddHistMod );
                }

                if ( pwdRemHistMod != null )
                {
                    mods.add( pwdRemHistMod );
                }

                if ( policyConfig.isPwdMustChange() )
                {
                    Attribute pwdMustChangeAt = new DefaultAttribute( pwdResetAT );
                    Modification pwdMustChangeMod;

                    if ( modifyContext.getSession().isAnAdministrator() )
                    {
                        pwdMustChangeAt.add( "TRUE" );
                        pwdMustChangeMod = new DefaultModification( REPLACE_ATTRIBUTE, pwdMustChangeAt );
                    }
                    else
                    {
                        pwdMustChangeMod = new DefaultModification( REMOVE_ATTRIBUTE, pwdMustChangeAt );
                        removePwdReset = true;
                    }

                    mods.add( pwdMustChangeMod );
                }
            }

            // Add the attributes that have been modified following a Add/Replace password
            processModifyAddPwdAttributes( entry, mods, pwdModDetails );

            String csnVal = directoryService.getCSN().toString();
            Modification csnMod = new DefaultModification( REPLACE_ATTRIBUTE, directoryService.getAtProvider()
                .getEntryCSN(), csnVal );
            mods.add( csnMod );

            ModifyOperationContext internalModifyCtx = new ModifyOperationContext( adminSession );
            internalModifyCtx.setPushToEvtInterceptor( true );
            internalModifyCtx.setDn( modifyContext.getDn() );
            internalModifyCtx.setEntry( entry );
            internalModifyCtx.setModItems( mods );

            internalModify( modifyContext, internalModifyCtx );

            if ( removePwdReset || pwdModDetails.isDelete() )
            {
                userSession.setPwdMustChange( false );
            }
        }
    }