class LdapAttrPlugin extends AbstractLdapPlugin {

    private static final Logger LOGGER = Logger.getLogger(LdapAttrPlugin.class.getName());

    /**
     * List of configuration names.
     * <ul>
     * <li><code>attribute</code> is LDAP attribute to check (mandatory)</li>
     * <li><code>file</code> whitelist file (mandatory)</li>
     * <li><code>instance</code> is number of <code>LdapUserInstance</code> plugin to use (optional)</li>
     * </ul>
     */
    static final String ATTR_PARAM = "attribute";
    static final String FILE_PARAM = "file";
    static final String INSTANCE_PARAM = "instance";

    private static final String SESSION_ALLOWED_PREFIX = "opengrok-ldap-attr-plugin-allowed";
    private String sessionAllowed = SESSION_ALLOWED_PREFIX;

    private String ldapAttr;
    private final Set<String> whitelist = new TreeSet<>();
    private Integer ldapUserInstance;
    private String filePath;

    public LdapAttrPlugin() {
        sessionAllowed += "-" + nextId++;
    }

    // for testing
    void load(Map<String, Object> parameters, AbstractLdapProvider provider) {
        super.load(provider);

        init(parameters);
    }

    @Override
    public void load(Map<String, Object> parameters) {
        super.load(parameters);

        init(parameters);
    }

    private void init(Map<String, Object> parameters) {<FILL_FUNCTION_BODY>}

    @Override
    protected boolean sessionExists(HttpServletRequest req) {
        return super.sessionExists(req)
                && req.getSession().getAttribute(sessionAllowed) != null;
    }

    String getSessionAllowedAttrName() {
        return sessionAllowed;
    }

    @Override
    public void fillSession(HttpServletRequest req, User user) {
        updateSession(req, false);

        LdapUser ldapUser = (LdapUser) req.getSession().getAttribute(LdapUserPlugin.getSessionAttrName(ldapUserInstance));
        if (ldapUser == null) {
            LOGGER.log(Level.WARNING, "cannot get {0} attribute from {1}",
                    new Object[]{LdapUserPlugin.SESSION_ATTR, user});
            return;
        }

        // Check attributes cached in LDAP user object first, then query LDAP server
        // (and if found, cache the result in the LDAP user object).
        Set<String> attributeValues = ldapUser.getAttribute(ldapAttr);
        if (attributeValues == null) {
            Map<String, Set<String>> records = null;
            AbstractLdapProvider ldapProvider = getLdapProvider();
            try {
                String dn = ldapUser.getDn();
                if (dn != null) {
                    LOGGER.log(Level.FINEST, "searching with dn={0} on {1}",
                            new Object[]{dn, ldapProvider});
                    AbstractLdapProvider.LdapSearchResult<Map<String, Set<String>>> res;
                    if ((res = ldapProvider.lookupLdapContent(dn, new String[]{ldapAttr})) == null) {
                        LOGGER.log(Level.WARNING, "cannot lookup attributes {0} for user {1} on {2})",
                                new Object[]{ldapAttr, ldapUser, ldapProvider});
                        return;
                    }

                    records = res.getAttrs();
                } else {
                    LOGGER.log(Level.FINE, "no DN for LDAP user {0} on {1}",
                            new Object[]{ldapUser, ldapProvider});
                }
            } catch (LdapException ex) {
                throw new AuthorizationException(ex);
            }

            if (records == null || records.isEmpty() || (attributeValues = records.get(ldapAttr)) == null) {
                LOGGER.log(Level.WARNING, "empty records or attribute values {0} for user {1} on {2}",
                        new Object[]{ldapAttr, ldapUser, ldapProvider});
                return;
            }

            ldapUser.setAttribute(ldapAttr, attributeValues);
        }

        boolean isAttrInWhitelist = attributeValues.stream().anyMatch(whitelist::contains);
        LOGGER.log(Level.FINEST, "LDAP user {0} {1} against {2}",
                new Object[]{ldapUser, isAttrInWhitelist ? "allowed" : "denied", filePath});
        updateSession(req, isAttrInWhitelist);
    }

    /**
     * Add a new allowed value into the session.
     *
     * @param req the request
     * @param allowed the new value
     */
    private void updateSession(HttpServletRequest req, boolean allowed) {
        req.getSession().setAttribute(sessionAllowed, allowed);
    }

    @Override
    public boolean checkEntity(HttpServletRequest request, Project project) {
        return ((Boolean) Objects.requireNonNullElse(request.getSession().getAttribute(sessionAllowed), false));
    }

    @Override
    public boolean checkEntity(HttpServletRequest request, Group group) {
        return ((Boolean) Objects.requireNonNullElse(request.getSession().getAttribute(sessionAllowed), false));
    }
}

        if ((ldapAttr = (String) parameters.get(ATTR_PARAM)) == null) {
            throw new NullPointerException("Missing param [" + ATTR_PARAM + "] in the setup");
        }

        if ((filePath = (String) parameters.get(FILE_PARAM)) == null) {
            throw new NullPointerException("Missing param [" + FILE_PARAM + "] in the setup");
        }

        String instance = (String) parameters.get(INSTANCE_PARAM);
        if (instance != null) {
            ldapUserInstance = Integer.parseInt(instance);
        }

        try (Stream<String> stream = Files.lines(Paths.get(filePath))) {
            stream.forEach(whitelist::add);
        } catch (IOException e) {
            throw new IllegalArgumentException(String.format("Unable to read the file \"%s\"", filePath), e);
        }

        LOGGER.log(Level.FINE, "LdapAttrPlugin plugin loaded with attr={0}, whitelist={1} ({2} entries), " +
                        "instance={3}", new Object[]{ldapAttr, filePath, whitelist.size(), ldapUserInstance});
    
<methods>public abstract boolean checkEntity(HttpServletRequest, org.opengrok.indexer.configuration.Project) ,public abstract boolean checkEntity(HttpServletRequest, org.opengrok.indexer.configuration.Group) ,public abstract void fillSession(HttpServletRequest, opengrok.auth.plugin.entity.User) ,public opengrok.auth.plugin.configuration.Configuration getConfiguration() ,public opengrok.auth.plugin.ldap.AbstractLdapProvider getLdapProvider() ,public boolean isAllowed(HttpServletRequest, org.opengrok.indexer.configuration.Project) ,public boolean isAllowed(HttpServletRequest, org.opengrok.indexer.configuration.Group) ,public void load(Map<java.lang.String,java.lang.Object>) ,public void unload() <variables>protected static final java.lang.String CONFIGURATION_PARAM,private static final Map<java.lang.String,opengrok.auth.plugin.configuration.Configuration> LOADED_CONFIGURATIONS,private static final java.lang.String SESSION_PREFIX,private opengrok.auth.plugin.configuration.Configuration cfg,private opengrok.auth.plugin.ldap.AbstractLdapProvider ldapProvider,protected static long nextId,protected java.lang.String sessionEstablished,protected java.lang.String sessionUsername