'See abstract method documentation.'

def authenticate(self, email, username, password, options):

    log.debug(('LDAP    authenticate:    email    is    %s' % email))
    log.debug(('LDAP    authenticate:    username    is    %s' % username))
    log.debug(('LDAP    authenticate:    options    are    %s' % options))
    failure_mode = False
    if (options.get('continue-on-failure', 'False') == 'False'):
        failure_mode = None
    if _get_bool(options, 'login-use-username', False):
        if (username is None):
            log.debug('LDAP    authenticate:    username    must    be    used    to    login,    cannot    be    None')
            return (failure_mode, '', '')
    elif (email is None):
        log.debug('LDAP    authenticate:    email    must    be    used    to    login,    cannot    be    None')
        return (failure_mode, '', '')
    try:
        import ldap
    except:
        log.debug('LDAP    authenticate:    could    not    load    ldap    module')
        return (failure_mode, '', '')
    params = {'email': email, 'username': username, 'password': password}
    try:
        ldap_options_raw = _get_subs(options, 'ldap-options', params)
    except ConfigurationError:
        ldap_options = ()
    else:
        ldap_options = _parse_ldap_options(ldap, ldap_options_raw)
    try:
        ldap.set_option(ldap.OPT_REFERRALS, 0)
        for opt in ldap_options:
            ldap.set_option(*opt)
    except Exception:
        log.exception('LDAP    authenticate:    set_option    exception')
        return (failure_mode, '', '')
    if ('search-fields' in options):
        try:
            l = ldap.initialize(_get_subs(options, 'server', params))
            l.protocol_version = 3
            if ('search-user' in options):
                l.simple_bind_s(_get_subs(options, 'search-user', params), _get_subs(options, 'search-password', params))
            else:
                l.simple_bind_s()
            attributes = [_.strip().format(**params) for _ in options['search-fields'].split(',')]
            suser = l.search_ext_s(_get_subs(options, 'search-base', params), ldap.SCOPE_SUBTREE, _get_subs(options, 'search-filter', params), attributes, timeout=60, sizelimit=1)
            if ((suser is None) or (len(suser) == 0)):
                log.warning('LDAP    authenticate:    search    returned    no    results')
                return (failure_mode, '', '')
            (dn, attrs) = suser[0]
            log.debug(('LDAP    authenticate:    dn    is    %s' % dn))
            log.debug(('LDAP    authenticate:    search    attributes    are    %s' % attrs))
            if hasattr(attrs, 'has_key'):
                for attr in attributes:
                    if (attr in attrs):
                        params[attr] = str(attrs[attr][0])
                    else:
                        params[attr] = ''
            params['dn'] = dn
        except Exception:
            log.exception('LDAP    authenticate:    search    exception')
            return (failure_mode, '', '')
    try:
        l = ldap.initialize(_get_subs(options, 'server', params))
        l.protocol_version = 3
        bind_password = _get_subs(options, 'bind-password', params)
        l.simple_bind_s(_get_subs(options, 'bind-user', params), bind_password)
        try:
            whoami = l.whoami_s()
        except ldap.PROTOCOL_ERROR:
            pass
        else:
            log.debug('LDAP    authenticate:    whoami    is    %s', whoami)
            if (whoami is None):
                raise RuntimeError('LDAP    authenticate:    anonymous    bind')
    except Exception:
        log.warning('LDAP    authenticate:    bind    exception', exc_info=True)
        return (failure_mode, '', '')
    log.debug('LDAP    authentication    successful')
    return (True, _get_subs(options, 'auto-register-email', params), _get_subs(options, 'auto-register-username', params))
