public function authenticate(array $data, HTTPRequest $request, ValidationResult &$result = null)
    {
        $result = $result ?: ValidationResult::create();
        /** @var LDAPService $service */
        $service = Injector::inst()->get(LDAPService::class);
        $login = trim($data['Login']);
        if (Email::is_valid_address($login)) {
            if (Config::inst()->get(self::class, 'allow_email_login') != 'yes') {
                $result->addError(
                    _t(
                        __CLASS__ . '.PLEASEUSEUSERNAME',
                        'Please enter your username instead of your email to log in.'
                    )
                );
                return null;
            }
            $username = $service->getUsernameByEmail($login);

            // No user found with this email.
            if (!$username) {
                if (Config::inst()->get(self::class, 'fallback_authenticator') === 'yes') {
                    if ($fallbackMember = $this->fallbackAuthenticate($data, $request)) {
                        {
                            return $fallbackMember;
                        }
                    }
                }

                $result->addError(_t(__CLASS__ . '.INVALIDCREDENTIALS', 'Invalid credentials'));
                return null;
            }
        } else {
            $username = $login;
        }

        $serviceAuthenticationResult = $service->authenticate($username, $data['Password']);
        $success = $serviceAuthenticationResult['success'] === true;

        if (!$success) {
            /*
             * Try the fallback method if admin or it failed for anything other than invalid credentials
             * This is to avoid having an unhandled exception error thrown by PasswordEncryptor::create_for_algorithm()
             */
            if (Config::inst()->get(self::class, 'fallback_authenticator') === 'yes') {
                if (!in_array($serviceAuthenticationResult['code'], [Result::FAILURE_CREDENTIAL_INVALID])
                    || $username === 'admin'
                ) {
                    if ($fallbackMember = $this->fallbackAuthenticate($data, $request)) {
                        return $fallbackMember;
                    }
                }
            }

            $result->addError($serviceAuthenticationResult['message']);

            return null;
        }
        $data = $service->getUserByUsername($serviceAuthenticationResult['identity']);
        if (!$data) {
            $result->addError(
                _t(
                    __CLASS__ . '.PROBLEMFINDINGDATA',
                    'There was a problem retrieving your user data'
                )
            );
            return null;
        }

        // LDAPMemberExtension::memberLoggedIn() will update any other AD attributes mapped to Member fields
        $member = Member::get()->filter('GUID', $data['objectguid'])->limit(1)->first();
        if (!($member && $member->exists())) {
            $member = new Member();
            $member->GUID = $data['objectguid'];
        }

        // Update the users from LDAP so we are sure that the email is correct.
        // This will also write the Member record.
        $service->updateMemberFromLDAP($member, $data);

        $request->getSession()->clear('BackURL');

        return $member;
    }