Shinsuke Sugaya %!s(int64=9) %!d(string=hai) anos
pai
achega
7abc25954e

+ 202 - 8
src/main/java/org/codelibs/fess/helper/RoleQueryHelper.java

@@ -15,15 +15,209 @@
  */
  */
 package org.codelibs.fess.helper;
 package org.codelibs.fess.helper;
 
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.Set;
 
 
-public interface RoleQueryHelper {
+import javax.annotation.PostConstruct;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
 
 
-    /**
-     * Returns roles.
-     *
-     * @return a list of a role. (not null)
-     */
-    Set<String> build();
+import org.codelibs.core.crypto.CachedCipher;
+import org.codelibs.core.lang.StringUtil;
+import org.codelibs.fess.mylasta.action.FessUserBean;
+import org.codelibs.fess.util.ComponentUtil;
+import org.codelibs.fess.util.StreamUtil;
+import org.lastaflute.web.servlet.request.RequestManager;
+import org.lastaflute.web.util.LaRequestUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 
-}
+/**
+ * This class returns a list of a role from a request parameter,
+ * a request header and a cookie. The format of the default value
+ * is "[\d]+\nrole1,role2,role3", which you can encrypt.
+ *
+ * @author shinsuke
+ *
+ */
+public class RoleQueryHelper {
+
+    private static final Logger logger = LoggerFactory.getLogger(RoleQueryHelper.class);
+
+    public CachedCipher cipher;
+
+    public String valueSeparator = "\n";
+
+    public String roleSeparator = ",";
+
+    public String parameterKey;
+
+    public boolean encryptedParameterValue = true;
+
+    public String headerKey;
+
+    public boolean encryptedHeaderValue = true;
+
+    public String cookieKey;
+
+    public boolean encryptedCookieValue = true;
+
+    protected Map<String, String> cookieNameMap;
+
+    private final List<String> defaultRoleList = new ArrayList<>();
+
+    @PostConstruct
+    public void init() {
+        StreamUtil.of(ComponentUtil.getFessConfig().getSearchDefaultRoles().split(",")).filter(name -> StringUtil.isNotBlank(name))
+                .forEach(name -> {
+                    defaultRoleList.add(name);
+                });
+    }
+
+    public Set<String> build() {
+        final Set<String> roleList = new HashSet<>();
+        final HttpServletRequest request = LaRequestUtil.getOptionalRequest().orElse(null);
+
+        // request parameter
+        if (request != null && StringUtil.isNotBlank(parameterKey)) {
+            roleList.addAll(buildByParameter(request));
+        }
+
+        // request header
+        if (request != null && StringUtil.isNotBlank(headerKey)) {
+            roleList.addAll(buildByHeader(request));
+        }
+
+        // cookie
+        if (request != null && StringUtil.isNotBlank(cookieKey)) {
+            roleList.addAll(buildByCookie(request));
+        }
+
+        // cookie mapping
+        if (cookieNameMap != null) {
+            roleList.addAll(buildByCookieNameMapping(request));
+        }
+
+        final RequestManager requestManager = ComponentUtil.getRequestManager();
+        requestManager.findUserBean(FessUserBean.class).ifPresent(
+                fessUserBean -> StreamUtil.of(fessUserBean.getRoles()).forEach(roleList::add));
+
+        if (defaultRoleList != null) {
+            roleList.addAll(defaultRoleList);
+        }
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("roleList: " + roleList);
+        }
+
+        return roleList;
+    }
+
+    protected Set<String> buildByParameter(final HttpServletRequest request) {
+
+        final String parameter = request.getParameter(parameterKey);
+        if (logger.isDebugEnabled()) {
+            logger.debug(parameterKey + ":" + parameter);
+        }
+        if (StringUtil.isNotEmpty(parameter)) {
+            return decodedRoleList(parameter, encryptedParameterValue);
+        }
+
+        return Collections.emptySet();
+    }
+
+    protected Set<String> buildByHeader(final HttpServletRequest request) {
+
+        final String parameter = request.getHeader(headerKey);
+        if (logger.isDebugEnabled()) {
+            logger.debug(headerKey + ":" + parameter);
+        }
+        if (StringUtil.isNotEmpty(parameter)) {
+            return decodedRoleList(parameter, encryptedHeaderValue);
+        }
+
+        return Collections.emptySet();
+
+    }
+
+    protected Set<String> buildByCookie(final HttpServletRequest request) {
+
+        final Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (final Cookie cookie : cookies) {
+                if (cookieKey.equals(cookie.getName())) {
+                    final String value = cookie.getValue();
+                    if (logger.isDebugEnabled()) {
+                        logger.debug(cookieKey + ":" + value);
+                    }
+                    if (StringUtil.isNotEmpty(value)) {
+                        return decodedRoleList(value, encryptedCookieValue);
+                    }
+                }
+            }
+        }
+
+        return Collections.emptySet();
+    }
+
+    protected Set<String> buildByCookieNameMapping(final HttpServletRequest request) {
+
+        final Set<String> roleNameSet = new HashSet<>();
+        final Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (final Cookie cookie : cookies) {
+                addRoleFromCookieMapping(roleNameSet, cookie);
+            }
+        }
+
+        return roleNameSet;
+    }
+
+    protected void addRoleFromCookieMapping(final Set<String> roleNameList, final Cookie cookie) {
+        final String roleName = cookieNameMap.get(cookie.getName());
+        if (StringUtil.isNotBlank(roleName)) {
+            roleNameList.add(roleName);
+        }
+    }
+
+    protected Set<String> decodedRoleList(final String value, final boolean encrypted) {
+        String rolesStr = value;
+        if (encrypted && cipher != null) {
+            rolesStr = cipher.decryptoText(rolesStr);
+        }
+
+        final Set<String> roleSet = new HashSet<>();
+        if (valueSeparator.length() > 0) {
+            final String[] values = rolesStr.split(valueSeparator);
+            if (values.length > 1) {
+                final String[] roles = values[1].split(roleSeparator);
+                for (final String role : roles) {
+                    if (StringUtil.isNotEmpty(role)) {
+                        roleSet.add(role);
+                    }
+                }
+            }
+        } else {
+            final String[] roles = rolesStr.split(roleSeparator);
+            for (final String role : roles) {
+                if (StringUtil.isNotEmpty(role)) {
+                    roleSet.add(role);
+                }
+            }
+        }
+        return roleSet;
+    }
+
+    public void addCookieNameMapping(final String cookieName, final String roleName) {
+        if (cookieNameMap == null) {
+            cookieNameMap = new HashMap<String, String>();
+        }
+        cookieNameMap.put(cookieName, roleName);
+    }
+
+}

+ 2 - 10
src/main/java/org/codelibs/fess/helper/SambaHelper.java

@@ -51,20 +51,12 @@ public class SambaHelper {
 
 
     public String getAccountId(final SID sid) {
     public String getAccountId(final SID sid) {
         if (fessConfig.isAvailableSmbSidType(sid.getType())) {
         if (fessConfig.isAvailableSmbSidType(sid.getType())) {
-            return convert(sid.getType(), sid.getAccountName());
+            return createSearchRole(sid.getType(), sid.getAccountName());
         }
         }
         return null;
         return null;
     }
     }
 
 
-    public String getRoleByUser(final String name) {
-        return convert(SID_TYPE_USER, name);
-    }
-
-    public String getRoleByDomainGroup(final String name) {
-        return convert(SID_TYPE_DOM_GRP, name);
-    }
-
-    protected String convert(final int type, final String name) {
+    protected String createSearchRole(final int type, final String name) {
         return type + name;
         return type + name;
     }
     }
 }
 }

+ 16 - 0
src/main/java/org/codelibs/fess/helper/SystemHelper.java

@@ -272,4 +272,20 @@ public class SystemHelper implements Serializable {
     public void setupAdminHtmlData(TypicalAction action, ActionRuntime runtime) {
     public void setupAdminHtmlData(TypicalAction action, ActionRuntime runtime) {
         // nothing
         // nothing
     }
     }
+
+    public String getSearchRoleByUser(final String name) {
+        return createSearchRole(ComponentUtil.getFessConfig().getLdapRoleSearchUserPrefix(), name);
+    }
+
+    public String getSearchRoleByGroup(final String name) {
+        return createSearchRole(ComponentUtil.getFessConfig().getLdapRoleSearchGroupPrefix(), name);
+    }
+
+    public String getSearchRoleByRole(final String name) {
+        return createSearchRole(ComponentUtil.getFessConfig().getLdapRoleSearchRolePrefix(), name);
+    }
+
+    protected String createSearchRole(final String type, final String name) {
+        return type + name;
+    }
 }
 }

+ 127 - 4
src/main/java/org/codelibs/fess/helper/UserInfoHelper.java

@@ -15,15 +15,138 @@
  */
  */
 package org.codelibs.fess.helper;
 package org.codelibs.fess.helper;
 
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
+import java.util.UUID;
 
 
-public interface UserInfoHelper {
+import javax.annotation.Resource;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
 
 
-    String getUserCode();
+import org.codelibs.core.collection.LruHashMap;
+import org.codelibs.core.lang.StringUtil;
+import org.codelibs.fess.Constants;
+import org.codelibs.fess.mylasta.direction.FessConfig;
+import org.codelibs.fess.util.ComponentUtil;
+import org.lastaflute.web.util.LaRequestUtil;
+import org.lastaflute.web.util.LaResponseUtil;
 
 
-    void storeQueryId(String query, List<Map<String, Object>> documentItems);
+public class UserInfoHelper {
+    @Resource
+    protected SearchLogHelper searchLogHelper;
 
 
-    String[] getResultDocIds(String queryId);
+    public int resultDocIdsCacheSize = 20;
 
 
+    public String cookieName = "fsid";
+
+    public String cookieDomain;
+
+    public int cookieMaxAge = 30 * 24 * 60 * 60;// 1 month
+
+    public String cookiePath;
+
+    public Boolean cookieSecure;
+
+    public String getUserCode() {
+        final HttpServletRequest request = LaRequestUtil.getRequest();
+
+        String userCode = (String) request.getAttribute(Constants.USER_CODE);
+
+        if (StringUtil.isBlank(userCode)) {
+            userCode = getUserCodeFromCookie(request);
+        }
+
+        if (!request.isRequestedSessionIdValid()) {
+            return null;
+        }
+
+        if (StringUtil.isBlank(userCode)) {
+            userCode = getId();
+        }
+
+        if (StringUtil.isNotBlank(userCode)) {
+            updateUserSessionId(userCode);
+        }
+        return userCode;
+    }
+
+    protected String getId() {
+        return UUID.randomUUID().toString().replace("-", StringUtil.EMPTY);
+    }
+
+    protected void updateUserSessionId(final String userCode) {
+        searchLogHelper.updateUserInfo(userCode);
+
+        final HttpServletRequest request = LaRequestUtil.getRequest();
+        request.setAttribute(Constants.USER_CODE, userCode);
+
+        final Cookie cookie = new Cookie(cookieName, userCode);
+        cookie.setMaxAge(cookieMaxAge);
+        if (StringUtil.isNotBlank(cookieDomain)) {
+            cookie.setDomain(cookieDomain);
+        }
+        if (StringUtil.isNotBlank(cookiePath)) {
+            cookie.setPath(cookiePath);
+        }
+        if (cookieSecure != null) {
+            cookie.setSecure(cookieSecure);
+        }
+        LaResponseUtil.getResponse().addCookie(cookie);
+    }
+
+    protected String getUserCodeFromCookie(final HttpServletRequest request) {
+        final Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (final Cookie cookie : cookies) {
+                if (cookieName.equals(cookie.getName())) {
+                    return cookie.getValue();
+                }
+            }
+        }
+        return null;
+    }
+
+    public void storeQueryId(final String queryId, final List<Map<String, Object>> documentItems) {
+        final HttpSession session = LaRequestUtil.getRequest().getSession(false);
+        if (session != null) {
+            final FessConfig fessConfig = ComponentUtil.getFessConfig();
+
+            final List<String> docIdList = new ArrayList<String>();
+            for (final Map<String, Object> map : documentItems) {
+                final Object docId = map.get(fessConfig.getIndexFieldDocId());
+                if (docId != null && docId.toString().length() > 0) {
+                    docIdList.add(docId.toString());
+                }
+            }
+
+            if (!docIdList.isEmpty()) {
+                final Map<String, String[]> resultDocIdsCache = getResultDocIdsCache(session);
+                resultDocIdsCache.put(queryId, docIdList.toArray(new String[docIdList.size()]));
+            }
+        }
+    }
+
+    public String[] getResultDocIds(final String queryId) {
+        final HttpSession session = LaRequestUtil.getRequest().getSession(false);
+        if (session != null) {
+            final Map<String, String[]> resultUrlCache = getResultDocIdsCache(session);
+            final String[] urls = resultUrlCache.get(queryId);
+            if (urls != null) {
+                return urls;
+            }
+        }
+        return StringUtil.EMPTY_STRINGS;
+    }
+
+    private Map<String, String[]> getResultDocIdsCache(final HttpSession session) {
+        @SuppressWarnings("unchecked")
+        Map<String, String[]> resultDocIdsCache = (Map<String, String[]>) session.getAttribute(Constants.RESULT_DOC_ID_CACHE);
+        if (resultDocIdsCache == null) {
+            resultDocIdsCache = new LruHashMap<String, String[]>(resultDocIdsCacheSize);
+            session.setAttribute(Constants.RESULT_DOC_ID_CACHE, resultDocIdsCache);
+        }
+        return resultDocIdsCache;
+    }
 }
 }

+ 0 - 161
src/main/java/org/codelibs/fess/helper/impl/CookieUserInfoHelperImpl.java

@@ -1,161 +0,0 @@
-/*
- * Copyright 2012-2016 CodeLibs Project and the Others.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language
- * governing permissions and limitations under the License.
- */
-package org.codelibs.fess.helper.impl;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import javax.annotation.Resource;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
-
-import org.codelibs.core.collection.LruHashMap;
-import org.codelibs.core.lang.StringUtil;
-import org.codelibs.fess.Constants;
-import org.codelibs.fess.helper.SearchLogHelper;
-import org.codelibs.fess.helper.UserInfoHelper;
-import org.codelibs.fess.mylasta.direction.FessConfig;
-import org.codelibs.fess.util.ComponentUtil;
-import org.lastaflute.web.util.LaRequestUtil;
-import org.lastaflute.web.util.LaResponseUtil;
-
-public class CookieUserInfoHelperImpl implements UserInfoHelper {
-
-    @Resource
-    protected SearchLogHelper searchLogHelper;
-
-    public int resultDocIdsCacheSize = 20;
-
-    public String cookieName = "fsid";
-
-    public String cookieDomain;
-
-    public int cookieMaxAge = 30 * 24 * 60 * 60;// 1 month
-
-    public String cookiePath;
-
-    public Boolean cookieSecure;
-
-    /* (non-Javadoc)
-     * @see org.codelibs.fess.helper.impl.UserInfoHelper#getUserCode()
-     */
-    @Override
-    public String getUserCode() {
-        final HttpServletRequest request = LaRequestUtil.getRequest();
-
-        String userCode = (String) request.getAttribute(Constants.USER_CODE);
-
-        if (StringUtil.isBlank(userCode)) {
-            userCode = getUserCodeFromCookie(request);
-        }
-
-        if (!request.isRequestedSessionIdValid()) {
-            return null;
-        }
-
-        if (StringUtil.isBlank(userCode)) {
-            userCode = getId();
-        }
-
-        if (StringUtil.isNotBlank(userCode)) {
-            updateUserSessionId(userCode);
-        }
-        return userCode;
-    }
-
-    protected String getId() {
-        return UUID.randomUUID().toString().replace("-", StringUtil.EMPTY);
-    }
-
-    protected void updateUserSessionId(final String userCode) {
-        searchLogHelper.updateUserInfo(userCode);
-
-        final HttpServletRequest request = LaRequestUtil.getRequest();
-        request.setAttribute(Constants.USER_CODE, userCode);
-
-        final Cookie cookie = new Cookie(cookieName, userCode);
-        cookie.setMaxAge(cookieMaxAge);
-        if (StringUtil.isNotBlank(cookieDomain)) {
-            cookie.setDomain(cookieDomain);
-        }
-        if (StringUtil.isNotBlank(cookiePath)) {
-            cookie.setPath(cookiePath);
-        }
-        if (cookieSecure != null) {
-            cookie.setSecure(cookieSecure);
-        }
-        LaResponseUtil.getResponse().addCookie(cookie);
-    }
-
-    protected String getUserCodeFromCookie(final HttpServletRequest request) {
-        final Cookie[] cookies = request.getCookies();
-        if (cookies != null) {
-            for (final Cookie cookie : cookies) {
-                if (cookieName.equals(cookie.getName())) {
-                    return cookie.getValue();
-                }
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public void storeQueryId(final String queryId, final List<Map<String, Object>> documentItems) {
-        final HttpSession session = LaRequestUtil.getRequest().getSession(false);
-        if (session != null) {
-            final FessConfig fessConfig = ComponentUtil.getFessConfig();
-
-            final List<String> docIdList = new ArrayList<String>();
-            for (final Map<String, Object> map : documentItems) {
-                final Object docId = map.get(fessConfig.getIndexFieldDocId());
-                if (docId != null && docId.toString().length() > 0) {
-                    docIdList.add(docId.toString());
-                }
-            }
-
-            if (!docIdList.isEmpty()) {
-                final Map<String, String[]> resultDocIdsCache = getResultDocIdsCache(session);
-                resultDocIdsCache.put(queryId, docIdList.toArray(new String[docIdList.size()]));
-            }
-        }
-    }
-
-    @Override
-    public String[] getResultDocIds(final String queryId) {
-        final HttpSession session = LaRequestUtil.getRequest().getSession(false);
-        if (session != null) {
-            final Map<String, String[]> resultUrlCache = getResultDocIdsCache(session);
-            final String[] urls = resultUrlCache.get(queryId);
-            if (urls != null) {
-                return urls;
-            }
-        }
-        return StringUtil.EMPTY_STRINGS;
-    }
-
-    private Map<String, String[]> getResultDocIdsCache(final HttpSession session) {
-        @SuppressWarnings("unchecked")
-        Map<String, String[]> resultDocIdsCache = (Map<String, String[]>) session.getAttribute(Constants.RESULT_DOC_ID_CACHE);
-        if (resultDocIdsCache == null) {
-            resultDocIdsCache = new LruHashMap<String, String[]>(resultDocIdsCacheSize);
-            session.setAttribute(Constants.RESULT_DOC_ID_CACHE, resultDocIdsCache);
-        }
-        return resultDocIdsCache;
-    }
-}

+ 0 - 231
src/main/java/org/codelibs/fess/helper/impl/RoleQueryHelperImpl.java

@@ -1,231 +0,0 @@
-/*
- * Copyright 2012-2016 CodeLibs Project and the Others.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- * either express or implied. See the License for the specific language
- * governing permissions and limitations under the License.
- */
-package org.codelibs.fess.helper.impl;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.PostConstruct;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-
-import org.codelibs.core.crypto.CachedCipher;
-import org.codelibs.core.lang.StringUtil;
-import org.codelibs.fess.helper.RoleQueryHelper;
-import org.codelibs.fess.mylasta.action.FessUserBean;
-import org.codelibs.fess.util.ComponentUtil;
-import org.codelibs.fess.util.StreamUtil;
-import org.lastaflute.web.servlet.request.RequestManager;
-import org.lastaflute.web.util.LaRequestUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * This class returns a list of a role from a request parameter,
- * a request header and a cookie. The format of the default value
- * is "[\d]+\nrole1,role2,role3", which you can encrypt.
- *
- * @author shinsuke
- *
- */
-public class RoleQueryHelperImpl implements RoleQueryHelper, Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    private static final Logger logger = LoggerFactory.getLogger(RoleQueryHelperImpl.class);
-
-    public CachedCipher cipher;
-
-    public String valueSeparator = "\n";
-
-    public String roleSeparator = ",";
-
-    public String parameterKey;
-
-    public boolean encryptedParameterValue = true;
-
-    public String headerKey;
-
-    public boolean encryptedHeaderValue = true;
-
-    public String cookieKey;
-
-    public boolean encryptedCookieValue = true;
-
-    protected Map<String, String> cookieNameMap;
-
-    private final List<String> defaultRoleList = new ArrayList<>();
-
-    @PostConstruct
-    public void init() {
-        StreamUtil.of(ComponentUtil.getFessConfig().getSearchDefaultRoles().split(",")).filter(name -> StringUtil.isNotBlank(name))
-                .forEach(name -> {
-                    defaultRoleList.add(name);
-                });
-    }
-
-    /* (non-Javadoc)
-     * @see org.codelibs.fess.helper.impl.RoleQueryHelper#build()
-     */
-    @Override
-    public Set<String> build() {
-        final Set<String> roleList = new HashSet<>();
-        final HttpServletRequest request = LaRequestUtil.getOptionalRequest().orElse(null);
-
-        // request parameter
-        if (request != null && StringUtil.isNotBlank(parameterKey)) {
-            roleList.addAll(buildByParameter(request));
-        }
-
-        // request header
-        if (request != null && StringUtil.isNotBlank(headerKey)) {
-            roleList.addAll(buildByHeader(request));
-        }
-
-        // cookie
-        if (request != null && StringUtil.isNotBlank(cookieKey)) {
-            roleList.addAll(buildByCookie(request));
-        }
-
-        // cookie mapping
-        if (cookieNameMap != null) {
-            roleList.addAll(buildByCookieNameMapping(request));
-        }
-
-        final RequestManager requestManager = ComponentUtil.getRequestManager();
-        requestManager.findUserBean(FessUserBean.class).ifPresent(
-                fessUserBean -> StreamUtil.of(fessUserBean.getRoles()).forEach(roleList::add));
-
-        if (defaultRoleList != null) {
-            roleList.addAll(defaultRoleList);
-        }
-
-        if (logger.isDebugEnabled()) {
-            logger.debug("roleList: " + roleList);
-        }
-
-        return roleList;
-    }
-
-    protected Set<String> buildByParameter(final HttpServletRequest request) {
-
-        final String parameter = request.getParameter(parameterKey);
-        if (logger.isDebugEnabled()) {
-            logger.debug(parameterKey + ":" + parameter);
-        }
-        if (StringUtil.isNotEmpty(parameter)) {
-            return decodedRoleList(parameter, encryptedParameterValue);
-        }
-
-        return Collections.emptySet();
-    }
-
-    protected Set<String> buildByHeader(final HttpServletRequest request) {
-
-        final String parameter = request.getHeader(headerKey);
-        if (logger.isDebugEnabled()) {
-            logger.debug(headerKey + ":" + parameter);
-        }
-        if (StringUtil.isNotEmpty(parameter)) {
-            return decodedRoleList(parameter, encryptedHeaderValue);
-        }
-
-        return Collections.emptySet();
-
-    }
-
-    protected Set<String> buildByCookie(final HttpServletRequest request) {
-
-        final Cookie[] cookies = request.getCookies();
-        if (cookies != null) {
-            for (final Cookie cookie : cookies) {
-                if (cookieKey.equals(cookie.getName())) {
-                    final String value = cookie.getValue();
-                    if (logger.isDebugEnabled()) {
-                        logger.debug(cookieKey + ":" + value);
-                    }
-                    if (StringUtil.isNotEmpty(value)) {
-                        return decodedRoleList(value, encryptedCookieValue);
-                    }
-                }
-            }
-        }
-
-        return Collections.emptySet();
-    }
-
-    protected Set<String> buildByCookieNameMapping(final HttpServletRequest request) {
-
-        final Set<String> roleNameSet = new HashSet<>();
-        final Cookie[] cookies = request.getCookies();
-        if (cookies != null) {
-            for (final Cookie cookie : cookies) {
-                addRoleFromCookieMapping(roleNameSet, cookie);
-            }
-        }
-
-        return roleNameSet;
-    }
-
-    protected void addRoleFromCookieMapping(final Set<String> roleNameList, final Cookie cookie) {
-        final String roleName = cookieNameMap.get(cookie.getName());
-        if (StringUtil.isNotBlank(roleName)) {
-            roleNameList.add(roleName);
-        }
-    }
-
-    protected Set<String> decodedRoleList(final String value, final boolean encrypted) {
-        String rolesStr = value;
-        if (encrypted && cipher != null) {
-            rolesStr = cipher.decryptoText(rolesStr);
-        }
-
-        final Set<String> roleSet = new HashSet<>();
-        if (valueSeparator.length() > 0) {
-            final String[] values = rolesStr.split(valueSeparator);
-            if (values.length > 1) {
-                final String[] roles = values[1].split(roleSeparator);
-                for (final String role : roles) {
-                    if (StringUtil.isNotEmpty(role)) {
-                        roleSet.add(role);
-                    }
-                }
-            }
-        } else {
-            final String[] roles = rolesStr.split(roleSeparator);
-            for (final String role : roles) {
-                if (StringUtil.isNotEmpty(role)) {
-                    roleSet.add(role);
-                }
-            }
-        }
-        return roleSet;
-    }
-
-    public void addCookieNameMapping(final String cookieName, final String roleName) {
-        if (cookieNameMap == null) {
-            cookieNameMap = new HashMap<String, String>();
-        }
-        cookieNameMap.put(cookieName, roleName);
-    }
-
-}

+ 329 - 146
src/main/java/org/codelibs/fess/ldap/LdapManager.java

@@ -18,6 +18,9 @@ package org.codelibs.fess.ldap;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.List;
+import java.util.Locale;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
 
 
 import javax.naming.Context;
 import javax.naming.Context;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingEnumeration;
@@ -28,6 +31,7 @@ import javax.naming.directory.BasicAttribute;
 import javax.naming.directory.BasicAttributes;
 import javax.naming.directory.BasicAttributes;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.InitialDirContext;
 import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.ModificationItem;
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 import javax.naming.directory.SearchResult;
 
 
@@ -37,9 +41,10 @@ import org.codelibs.fess.es.user.exentity.Group;
 import org.codelibs.fess.es.user.exentity.Role;
 import org.codelibs.fess.es.user.exentity.Role;
 import org.codelibs.fess.es.user.exentity.User;
 import org.codelibs.fess.es.user.exentity.User;
 import org.codelibs.fess.exception.LdapOperationException;
 import org.codelibs.fess.exception.LdapOperationException;
-import org.codelibs.fess.helper.SambaHelper;
+import org.codelibs.fess.helper.SystemHelper;
 import org.codelibs.fess.mylasta.direction.FessConfig;
 import org.codelibs.fess.mylasta.direction.FessConfig;
 import org.codelibs.fess.util.ComponentUtil;
 import org.codelibs.fess.util.ComponentUtil;
+import org.codelibs.fess.util.StreamUtil;
 import org.dbflute.optional.OptionalEntity;
 import org.dbflute.optional.OptionalEntity;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
@@ -47,6 +52,8 @@ import org.slf4j.LoggerFactory;
 public class LdapManager {
 public class LdapManager {
     private static final Logger logger = LoggerFactory.getLogger(LdapManager.class);
     private static final Logger logger = LoggerFactory.getLogger(LdapManager.class);
 
 
+    protected ThreadLocal<DirContextHolder> contextLocal = new ThreadLocal<>();
+
     public OptionalEntity<FessUser> login(final String username, final String password) {
     public OptionalEntity<FessUser> login(final String username, final String password) {
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
 
 
@@ -94,73 +101,74 @@ public class LdapManager {
     }
     }
 
 
     public String[] getRoles(final LdapUser ldapUser, final String bindDn, final String accountFilter) {
     public String[] getRoles(final LdapUser ldapUser, final String bindDn, final String accountFilter) {
-        final SambaHelper sambaHelper = ComponentUtil.getSambaHelper();
+        final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
         final List<String> roleList = new ArrayList<String>();
         final List<String> roleList = new ArrayList<String>();
 
 
-        if (fessConfig.isSmbRoleAsUser()) {
-            roleList.add(sambaHelper.getRoleByUser(ldapUser.getName()));
+        if (fessConfig.isLdapRoleSearchUserEnabled()) {
+            roleList.add(systemHelper.getSearchRoleByUser(ldapUser.getName()));
         }
         }
 
 
-        DirContext ctx = null;
-        try {
-            ctx = new InitialDirContext(ldapUser.getEnvironment());
-
-            // LDAP: cn=%s
-            // AD: (&(objectClass=user)(sAMAccountName=%s))
-            final String filter = String.format(accountFilter, ldapUser.getName());
-            final SearchControls controls = new SearchControls();
-            controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-
-            //search
-            final NamingEnumeration<SearchResult> rslt = ctx.search(bindDn, filter, controls);
-            while (rslt.hasMoreElements()) {
-                final SearchResult srcrslt = rslt.next();
-                final Attributes attrs = srcrslt.getAttributes();
-
-                //get group attr
-                final Attribute attr = attrs.get("memberOf");
-                if (attr == null) {
-                    continue;
+        // LDAP: cn=%s
+        // AD: (&(objectClass=user)(sAMAccountName=%s))
+        final String filter = String.format(accountFilter, ldapUser.getName());
+        search(bindDn, filter, new String[] { fessConfig.getLdapMemberofAttribute() }, result -> {
+            processSearchRoles(result, (entryDn, name) -> {
+                final boolean isRole = entryDn.toLowerCase(Locale.ROOT).indexOf("ou=role") != -1;
+                if (isRole) {
+                    if (fessConfig.isLdapRoleSearchRoleEnabled()) {
+                        roleList.add(systemHelper.getSearchRoleByRole(name));
+                    }
+                } else if (fessConfig.isLdapRoleSearchGroupEnabled()) {
+                    roleList.add(systemHelper.getSearchRoleByGroup(name));
                 }
                 }
+            });
+        });
 
 
-                for (int i = 0; i < attr.size(); i++) {
-                    final Object attrValue = attr.get(i);
-                    if (attrValue != null) {
-                        // TODO replace with regexp
-                        String strTmp = attrValue.toString();
+        return roleList.toArray(new String[roleList.size()]);
+    }
 
 
-                        int strStart = 0;
-                        int strEnd = 0;
+    protected void processSearchRoles(NamingEnumeration<SearchResult> result, BiConsumer<String, String> consumer) throws NamingException {
+        final FessConfig fessConfig = ComponentUtil.getFessConfig();
+        while (result.hasMoreElements()) {
+            final SearchResult srcrslt = result.next();
+            final Attributes attrs = srcrslt.getAttributes();
+
+            //get group attr
+            final Attribute attr = attrs.get(fessConfig.getLdapMemberofAttribute());
+            if (attr == null) {
+                continue;
+            }
 
 
-                        strStart = strTmp.indexOf("CN=");
-                        strStart += "CN=".length();
-                        strEnd = strTmp.indexOf(',');
+            for (int i = 0; i < attr.size(); i++) {
+                final Object attrValue = attr.get(i);
+                if (attrValue != null) {
+                    final String entryDn = attrValue.toString();
 
 
-                        strTmp = strTmp.substring(strStart, strEnd);
+                    int start = 0;
+                    int end = 0;
 
 
-                        if (fessConfig.isSmbRoleAsGroup()) {
-                            roleList.add(sambaHelper.getRoleByDomainGroup(strTmp));
-                        } else {
-                            roleList.add(strTmp);
-                        }
+                    start = entryDn.indexOf("CN=");
+                    if (start < 0) {
+                        start = entryDn.indexOf("cn=");
+                    }
+                    if (start == -1) {
+                        continue;
+                    }
+                    start += 3;
+                    end = entryDn.indexOf(',');
+
+                    String name;
+                    if (end == -1) {
+                        name = entryDn.substring(start);
+                    } else {
+                        name = entryDn.substring(start, end);
                     }
                     }
-                }
-            }
 
 
-        } catch (final Exception e) {
-            logger.warn("Failed to resolve roles: " + ldapUser.getName(), e);
-        } finally {
-            if (ctx != null) {
-                try {
-                    ctx.close();
-                } catch (final NamingException e) {
-                    // ignored
+                    consumer.accept(entryDn, name);
                 }
                 }
             }
             }
         }
         }
-
-        return roleList.toArray(new String[roleList.size()]);
     }
     }
 
 
     public void insert(User user) {
     public void insert(User user) {
@@ -169,29 +177,121 @@ public class LdapManager {
             return;
             return;
         }
         }
 
 
-        DirContext ctx = null;
-        try {
-            final Hashtable<String, String> env =
-                    createEnvironment(fessConfig.getLdapAdminInitialContextFactory(), fessConfig.getLdapAdminSecurityAuthentication(),
-                            fessConfig.getLdapAdminProviderUrl(), fessConfig.getLdapAdminSecurityPrincipal(),
-                            fessConfig.getLdapAdminSecurityCredentials());
-            ctx = new InitialDirContext(env);
-
-            BasicAttributes entry = new BasicAttributes();
-
-            String entryDN = fessConfig.getLdapAdminUserSecurityPrincipal(user.getName());
-
-            addUserAttributes(entry, user, fessConfig);
-
-            Attribute oc = fessConfig.getLdapAdminUserObjectClassAttribute();
-            entry.put(oc);
+        String userDN = fessConfig.getLdapAdminUserSecurityPrincipal(user.getName());
+        search(fessConfig.getLdapAdminUserBaseDn(), fessConfig.getLdapAdminUserFilter(user.getName()),
+                new String[] { fessConfig.getLdapMemberofAttribute() }, result -> {
+                    if (result.hasMore()) {
+                        if (user.getOriginalPassword() != null) {
+                            List<ModificationItem> modifyList = new ArrayList<>();
+                            modifyReplaceEntry(modifyList, "userPassword", user.getOriginalPassword());
+                            modify(userDN, modifyList);
+                        }
 
 
-            // TODO role and group
+                        List<String> oldGroupList = new ArrayList<>();
+                        List<String> oldRoleList = new ArrayList<>();
+                        String lowerGroupDn = fessConfig.getLdapAdminGroupBaseDn().toLowerCase(Locale.ROOT);
+                        String lowerRoleDn = fessConfig.getLdapAdminRoleBaseDn().toLowerCase(Locale.ROOT);
+                        processSearchRoles(result, (entryDn, name) -> {
+                            String lowerEntryDn = entryDn.toLowerCase(Locale.ROOT);
+                            if (lowerEntryDn.indexOf(lowerGroupDn) != -1) {
+                                oldGroupList.add(name);
+                            } else if (lowerEntryDn.indexOf(lowerRoleDn) != -1) {
+                                oldRoleList.add(name);
+                            }
+                        });
+
+                        List<String> newGroupList = StreamUtil.of(user.getGroupNames()).collect(Collectors.toList());
+                        StreamUtil.of(user.getGroupNames()).forEach(name -> {
+                            if (oldGroupList.contains(name)) {
+                                oldGroupList.remove(name);
+                                newGroupList.remove(name);
+                            }
+                        });
+                        oldGroupList.stream().forEach(name -> {
+                            search(fessConfig.getLdapAdminGroupBaseDn(), fessConfig.getLdapAdminGroupFilter(name), null, subResult -> {
+                                if (subResult.hasMore()) {
+                                    List<ModificationItem> modifyList = new ArrayList<>();
+                                    modifyDeleteEntry(modifyList, "member", userDN);
+                                    modify(fessConfig.getLdapAdminGroupSecurityPrincipal(name), modifyList);
+                                }
+                            });
+                        });
+                        newGroupList.stream().forEach(name -> {
+                            search(fessConfig.getLdapAdminGroupBaseDn(), fessConfig.getLdapAdminGroupFilter(name), null, subResult -> {
+                                if (!subResult.hasMore()) {
+                                    Group group = new Group();
+                                    group.setName(name);
+                                    insert(group);
+                                }
+                                List<ModificationItem> modifyList = new ArrayList<>();
+                                modifyAddEntry(modifyList, "member", userDN);
+                                modify(fessConfig.getLdapAdminGroupSecurityPrincipal(name), modifyList);
+                            });
+                        });
+
+                        List<String> newRoleList = StreamUtil.of(user.getRoleNames()).collect(Collectors.toList());
+                        StreamUtil.of(user.getRoleNames()).forEach(name -> {
+                            if (oldRoleList.contains(name)) {
+                                oldRoleList.remove(name);
+                                newRoleList.remove(name);
+                            }
+                        });
+                        oldRoleList.stream().forEach(name -> {
+                            search(fessConfig.getLdapAdminRoleBaseDn(), fessConfig.getLdapAdminRoleFilter(name), null, subResult -> {
+                                if (subResult.hasMore()) {
+                                    List<ModificationItem> modifyList = new ArrayList<>();
+                                    modifyDeleteEntry(modifyList, "member", userDN);
+                                    modify(fessConfig.getLdapAdminRoleSecurityPrincipal(name), modifyList);
+                                }
+                            });
+                        });
+                        newRoleList.stream().forEach(name -> {
+                            search(fessConfig.getLdapAdminRoleBaseDn(), fessConfig.getLdapAdminRoleFilter(name), null, subResult -> {
+                                if (!subResult.hasMore()) {
+                                    Role role = new Role();
+                                    role.setName(name);
+                                    insert(role);
+                                }
+                                List<ModificationItem> modifyList = new ArrayList<>();
+                                modifyAddEntry(modifyList, "member", userDN);
+                                modify(fessConfig.getLdapAdminRoleSecurityPrincipal(name), modifyList);
+                            });
+                        });
+                    } else {
+                        BasicAttributes entry = new BasicAttributes();
+                        addUserAttributes(entry, user, fessConfig);
+                        Attribute oc = fessConfig.getLdapAdminUserObjectClassAttribute();
+                        entry.put(oc);
+                        insert(userDN, entry);
+
+                        StreamUtil.of(user.getGroupNames()).forEach(name -> {
+                            search(fessConfig.getLdapAdminGroupBaseDn(), fessConfig.getLdapAdminGroupFilter(name), null, subResult -> {
+                                if (!subResult.hasMore()) {
+                                    Group group = new Group();
+                                    group.setName(name);
+                                    insert(group);
+                                }
+                                List<ModificationItem> modifyList = new ArrayList<>();
+                                modifyAddEntry(modifyList, "member", userDN);
+                                modify(fessConfig.getLdapAdminGroupSecurityPrincipal(name), modifyList);
+                            });
+                        });
+
+                        StreamUtil.of(user.getRoleNames()).forEach(name -> {
+                            search(fessConfig.getLdapAdminRoleBaseDn(), fessConfig.getLdapAdminRoleFilter(name), null, subResult -> {
+                                if (!subResult.hasMore()) {
+                                    Role role = new Role();
+                                    role.setName(name);
+                                    insert(role);
+                                }
+                                List<ModificationItem> modifyList = new ArrayList<>();
+                                modifyAddEntry(modifyList, "member", userDN);
+                                modify(fessConfig.getLdapAdminRoleSecurityPrincipal(name), modifyList);
+                            });
+                        });
+                    }
+                });
 
 
-            ctx.createSubcontext(entryDN, entry);
-        } catch (NamingException e) {
-            throw new LdapOperationException("Failed to add " + user, e);
-        }
     }
     }
 
 
     protected void addUserAttributes(final BasicAttributes entry, final User user, final FessConfig fessConfig) {
     protected void addUserAttributes(final BasicAttributes entry, final User user, final FessConfig fessConfig) {
@@ -206,20 +306,14 @@ public class LdapManager {
             return;
             return;
         }
         }
 
 
-        DirContext ctx = null;
-        try {
-            final Hashtable<String, String> env =
-                    createEnvironment(fessConfig.getLdapAdminInitialContextFactory(), fessConfig.getLdapAdminSecurityAuthentication(),
-                            fessConfig.getLdapAdminProviderUrl(), fessConfig.getLdapAdminSecurityPrincipal(),
-                            fessConfig.getLdapAdminSecurityCredentials());
-            ctx = new InitialDirContext(env);
-
-            String entryDN = fessConfig.getLdapAdminUserSecurityPrincipal(user.getName());
+        search(fessConfig.getLdapAdminUserBaseDn(), fessConfig.getLdapAdminUserFilter(user.getName()), null, result -> {
+            if (result.hasMore()) {
+                delete(fessConfig.getLdapAdminUserSecurityPrincipal(user.getName()));
+            } else {
+                logger.info("{} does not exist in LDAP server.", user.getName());
+            }
+        });
 
 
-            ctx.destroySubcontext(entryDN);
-        } catch (NamingException e) {
-            throw new LdapOperationException("Failed to delete " + user, e);
-        }
     }
     }
 
 
     public void insert(Role role) {
     public void insert(Role role) {
@@ -228,27 +322,19 @@ public class LdapManager {
             return;
             return;
         }
         }
 
 
-        DirContext ctx = null;
-        try {
-            final Hashtable<String, String> env =
-                    createEnvironment(fessConfig.getLdapAdminInitialContextFactory(), fessConfig.getLdapAdminSecurityAuthentication(),
-                            fessConfig.getLdapAdminProviderUrl(), fessConfig.getLdapAdminSecurityPrincipal(),
-                            fessConfig.getLdapAdminSecurityCredentials());
-            ctx = new InitialDirContext(env);
-
-            BasicAttributes entry = new BasicAttributes();
-
-            String entryDN = fessConfig.getLdapAdminRoleSecurityPrincipal(role.getName());
-
-            addRoleAttributes(entry, role, fessConfig);
-
-            Attribute oc = fessConfig.getLdapAdminRoleObjectClassAttribute();
-            entry.put(oc);
+        search(fessConfig.getLdapAdminRoleBaseDn(), fessConfig.getLdapAdminRoleFilter(role.getName()), null, result -> {
+            if (result.hasMore()) {
+                logger.info("{} exists in LDAP server.", role.getName());
+            } else {
+                String entryDN = fessConfig.getLdapAdminRoleSecurityPrincipal(role.getName());
+                BasicAttributes entry = new BasicAttributes();
+                addRoleAttributes(entry, role, fessConfig);
+                Attribute oc = fessConfig.getLdapAdminRoleObjectClassAttribute();
+                entry.put(oc);
+                insert(entryDN, entry);
+            }
+        });
 
 
-            ctx.createSubcontext(entryDN, entry);
-        } catch (NamingException e) {
-            throw new LdapOperationException("Failed to add " + role, e);
-        }
     }
     }
 
 
     protected void addRoleAttributes(final BasicAttributes entry, final Role user, final FessConfig fessConfig) {
     protected void addRoleAttributes(final BasicAttributes entry, final Role user, final FessConfig fessConfig) {
@@ -261,20 +347,15 @@ public class LdapManager {
             return;
             return;
         }
         }
 
 
-        DirContext ctx = null;
-        try {
-            final Hashtable<String, String> env =
-                    createEnvironment(fessConfig.getLdapAdminInitialContextFactory(), fessConfig.getLdapAdminSecurityAuthentication(),
-                            fessConfig.getLdapAdminProviderUrl(), fessConfig.getLdapAdminSecurityPrincipal(),
-                            fessConfig.getLdapAdminSecurityCredentials());
-            ctx = new InitialDirContext(env);
-
-            String entryDN = fessConfig.getLdapAdminRoleSecurityPrincipal(role.getName());
+        search(fessConfig.getLdapAdminRoleBaseDn(), fessConfig.getLdapAdminRoleFilter(role.getName()), null, result -> {
+            if (result.hasMore()) {
+                String entryDN = fessConfig.getLdapAdminRoleSecurityPrincipal(role.getName());
+                delete(entryDN);
+            } else {
+                logger.info("{} does not exist in LDAP server.", role.getName());
+            }
+        });
 
 
-            ctx.destroySubcontext(entryDN);
-        } catch (NamingException e) {
-            throw new LdapOperationException("Failed to delete " + role, e);
-        }
     }
     }
 
 
     public void insert(Group group) {
     public void insert(Group group) {
@@ -283,52 +364,154 @@ public class LdapManager {
             return;
             return;
         }
         }
 
 
-        DirContext ctx = null;
-        try {
-            final Hashtable<String, String> env =
-                    createEnvironment(fessConfig.getLdapAdminInitialContextFactory(), fessConfig.getLdapAdminSecurityAuthentication(),
-                            fessConfig.getLdapAdminProviderUrl(), fessConfig.getLdapAdminSecurityPrincipal(),
-                            fessConfig.getLdapAdminSecurityCredentials());
-            ctx = new InitialDirContext(env);
+        search(fessConfig.getLdapAdminGroupBaseDn(), fessConfig.getLdapAdminGroupFilter(group.getName()), null, result -> {
+            if (result.hasMore()) {
+                logger.info("{} exists in LDAP server.", group.getName());
+            } else {
+                String entryDN = fessConfig.getLdapAdminGroupSecurityPrincipal(group.getName());
+                BasicAttributes entry = new BasicAttributes();
+                addGroupAttributes(entry, group.getName(), fessConfig);
+                Attribute oc = fessConfig.getLdapAdminGroupObjectClassAttribute();
+                entry.put(oc);
+                insert(entryDN, entry);
+            }
+        });
+    }
 
 
-            BasicAttributes entry = new BasicAttributes();
+    protected void addGroupAttributes(final BasicAttributes entry, final String name, final FessConfig fessConfig) {
+        // nothing
+    }
 
 
-            String entryDN = fessConfig.getLdapAdminGroupSecurityPrincipal(group.getName());
+    public void delete(Group group) {
+        final FessConfig fessConfig = ComponentUtil.getFessConfig();
+        if (!fessConfig.isLdapAdminEnabled()) {
+            return;
+        }
 
 
-            addGroupAttributes(entry, group, fessConfig);
+        search(fessConfig.getLdapAdminGroupBaseDn(), fessConfig.getLdapAdminGroupFilter(group.getName()), null, result -> {
+            if (result.hasMore()) {
+                String entryDN = fessConfig.getLdapAdminGroupSecurityPrincipal(group.getName());
+                delete(entryDN);
+            } else {
+                logger.info("{} does not exist in LDAP server.", group.getName());
+            }
+        });
+    }
 
 
-            Attribute oc = fessConfig.getLdapAdminGroupObjectClassAttribute();
-            entry.put(oc);
+    protected void insert(String entryDN, Attributes entry) {
+        try (DirContextHolder holder = getDirContext()) {
+            logger.debug("Inserting {}", entryDN);
+            holder.get().createSubcontext(entryDN, entry);
+        } catch (NamingException e) {
+            throw new LdapOperationException("Failed to add " + entryDN, e);
+        }
+    }
 
 
-            ctx.createSubcontext(entryDN, entry);
+    protected void delete(String entryDN) {
+        try (DirContextHolder holder = getDirContext()) {
+            logger.debug("Deleting {}", entryDN);
+            holder.get().destroySubcontext(entryDN);
         } catch (NamingException e) {
         } catch (NamingException e) {
-            throw new LdapOperationException("Failed to add " + group, e);
+            throw new LdapOperationException("Failed to delete " + entryDN, e);
         }
         }
     }
     }
 
 
-    protected void addGroupAttributes(final BasicAttributes entry, final Group group, final FessConfig fessConfig) {
-        // nothing
+    protected void search(String baseDn, String filter, String[] returningAttrs, SearcConsumer consumer) {
+        try (DirContextHolder holder = getDirContext()) {
+            final SearchControls controls = new SearchControls();
+            controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+            if (returningAttrs != null) {
+                controls.setReturningAttributes(returningAttrs);
+            }
+
+            consumer.accept(holder.get().search(baseDn, filter, controls));
+        } catch (NamingException e) {
+            throw new LdapOperationException("Failed to search " + baseDn + " with " + filter, e);
+        }
     }
     }
 
 
-    public void delete(Group group) {
-        final FessConfig fessConfig = ComponentUtil.getFessConfig();
-        if (!fessConfig.isLdapAdminEnabled()) {
-            return;
+    protected void modifyAddEntry(List<ModificationItem> modifyList, String name, String value) {
+        Attribute attr = new BasicAttribute(name, value);
+        ModificationItem mod = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr);
+        modifyList.add(mod);
+    }
+
+    protected void modifyReplaceEntry(List<ModificationItem> modifyList, String name, String value) {
+        Attribute attr = new BasicAttribute(name, value);
+        ModificationItem mod = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr);
+        modifyList.add(mod);
+    }
+
+    protected void modifyDeleteEntry(List<ModificationItem> modifyList, String name, String value) {
+        Attribute attr = new BasicAttribute(name, value);
+        ModificationItem mod = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attr);
+        modifyList.add(mod);
+    }
+
+    protected void modify(String dn, List<ModificationItem> modifyList) {
+        try (DirContextHolder holder = getDirContext()) {
+            holder.get().modifyAttributes(dn, modifyList.toArray(new ModificationItem[modifyList.size()]));
+        } catch (NamingException e) {
+            throw new LdapOperationException("Failed to search " + dn, e);
         }
         }
+    }
 
 
-        DirContext ctx = null;
-        try {
+    interface SearcConsumer {
+        void accept(NamingEnumeration<SearchResult> t) throws NamingException;
+    }
+
+    protected DirContextHolder getDirContext() {
+        DirContextHolder holder = contextLocal.get();
+        if (holder == null) {
+            final FessConfig fessConfig = ComponentUtil.getFessConfig();
             final Hashtable<String, String> env =
             final Hashtable<String, String> env =
                     createEnvironment(fessConfig.getLdapAdminInitialContextFactory(), fessConfig.getLdapAdminSecurityAuthentication(),
                     createEnvironment(fessConfig.getLdapAdminInitialContextFactory(), fessConfig.getLdapAdminSecurityAuthentication(),
                             fessConfig.getLdapAdminProviderUrl(), fessConfig.getLdapAdminSecurityPrincipal(),
                             fessConfig.getLdapAdminProviderUrl(), fessConfig.getLdapAdminSecurityPrincipal(),
                             fessConfig.getLdapAdminSecurityCredentials());
                             fessConfig.getLdapAdminSecurityCredentials());
-            ctx = new InitialDirContext(env);
+            try {
+                holder = new DirContextHolder(new InitialDirContext(env));
+                contextLocal.set(holder);
+                return holder;
+            } catch (NamingException e) {
+                throw new LdapOperationException("Failed to create DirContext.", e);
+            }
+        } else {
+            holder.inc();
+            return holder;
+        }
+    }
 
 
-            String entryDN = fessConfig.getLdapAdminGroupSecurityPrincipal(group.getName());
+    protected class DirContextHolder implements AutoCloseable {
+        private DirContext context;
 
 
-            ctx.destroySubcontext(entryDN);
-        } catch (NamingException e) {
-            throw new LdapOperationException("Failed to delete " + group, e);
+        private int counter = 1;
+
+        protected DirContextHolder(DirContext context) {
+            this.context = context;
+        }
+
+        public DirContext get() {
+            return context;
+        }
+
+        public void inc() {
+            counter++;
+        }
+
+        @Override
+        public void close() {
+            if (counter > 1) {
+                counter--;
+            } else {
+                contextLocal.remove();
+                if (context != null) {
+                    try {
+                        context.close();
+                    } catch (final NamingException e) {
+                        // ignored
+                    }
+                }
+            }
         }
         }
     }
     }
 }
 }

+ 0 - 6
src/main/java/org/codelibs/fess/mylasta/action/FessHtmlPath.java

@@ -317,12 +317,6 @@ public interface FessHtmlPath {
     /** The path of the HTML: /index.jsp */
     /** The path of the HTML: /index.jsp */
     HtmlNext path_IndexJsp = new HtmlNext("/index.jsp");
     HtmlNext path_IndexJsp = new HtmlNext("/index.jsp");
 
 
-    /** The path of the HTML: /info/login_info.jsp */
-    HtmlNext path_Info_LoginInfoJsp = new HtmlNext("/info/login_info.jsp");
-
-    /** The path of the HTML: /info/search_info.jsp */
-    HtmlNext path_Info_SearchInfoJsp = new HtmlNext("/info/search_info.jsp");
-
     /** The path of the HTML: /login/footer.jsp */
     /** The path of the HTML: /login/footer.jsp */
     HtmlNext path_Login_FooterJsp = new HtmlNext("/login/footer.jsp");
     HtmlNext path_Login_FooterJsp = new HtmlNext("/login/footer.jsp");
 
 

+ 3 - 0
src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java

@@ -2031,6 +2031,9 @@ public class FessLabels extends ActionMessages {
     /** The key of the message: Notification */
     /** The key of the message: Notification */
     public static final String LABELS_general_menu_notification = "{labels.general_menu_notification}";
     public static final String LABELS_general_menu_notification = "{labels.general_menu_notification}";
 
 
+    /** The key of the message: Send TestMail */
+    public static final String LABELS_send_testmail = "{labels.send_testmail}";
+
     /** The key of the message: Back Up */
     /** The key of the message: Back Up */
     public static final String LABELS_backup_configuration = "{labels.backup_configuration}";
     public static final String LABELS_backup_configuration = "{labels.backup_configuration}";
 
 

+ 218 - 71
src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java

@@ -380,12 +380,6 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     /** The key of the configuration. e.g. true */
     /** The key of the configuration. e.g. true */
     String SMB_ROLE_FROM_FILE = "smb.role.from.file";
     String SMB_ROLE_FROM_FILE = "smb.role.from.file";
 
 
-    /** The key of the configuration. e.g. true */
-    String SMB_ROLE_AS_USER = "smb.role.as.user";
-
-    /** The key of the configuration. e.g. true */
-    String SMB_ROLE_AS_GROUP = "smb.role.as.group";
-
     /** The key of the configuration. e.g. 1,2 */
     /** The key of the configuration. e.g. 1,2 */
     String SMB_AVAILABLE_SID_TYPES = "smb.available.sid.types";
     String SMB_AVAILABLE_SID_TYPES = "smb.available.sid.types";
 
 
@@ -632,24 +626,54 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     /** The key of the configuration. e.g. password */
     /** The key of the configuration. e.g. password */
     String LDAP_ADMIN_SECURITY_CREDENTIALS = "ldap.admin.security.credentials";
     String LDAP_ADMIN_SECURITY_CREDENTIALS = "ldap.admin.security.credentials";
 
 
-    /** The key of the configuration. e.g. uid=%s,ou=People,dc=fess,dc=codelibs,dc=org */
-    String LDAP_ADMIN_USER_SECURITY_PRINCIPAL = "ldap.admin.user.security.principal";
+    /** The key of the configuration. e.g. uid=%s */
+    String LDAP_ADMIN_USER_FILTER = "ldap.admin.user.filter";
+
+    /** The key of the configuration. e.g. ou=People,dc=fess,dc=codelibs,dc=org */
+    String LDAP_ADMIN_USER_BASE_DN = "ldap.admin.user.base.dn";
 
 
     /** The key of the configuration. e.g. organizationalPerson,top,person,inetOrgPerson */
     /** The key of the configuration. e.g. organizationalPerson,top,person,inetOrgPerson */
     String LDAP_ADMIN_USER_OBJECT_CLASSES = "ldap.admin.user.object.classes";
     String LDAP_ADMIN_USER_OBJECT_CLASSES = "ldap.admin.user.object.classes";
 
 
-    /** The key of the configuration. e.g. cn=%s,ou=Role,dc=fess,dc=codelibs,dc=org */
-    String LDAP_ADMIN_ROLE_SECURITY_PRINCIPAL = "ldap.admin.role.security.principal";
+    /** The key of the configuration. e.g. cn=%s */
+    String LDAP_ADMIN_ROLE_FILTER = "ldap.admin.role.filter";
+
+    /** The key of the configuration. e.g. ou=Role,dc=fess,dc=codelibs,dc=org */
+    String LDAP_ADMIN_ROLE_BASE_DN = "ldap.admin.role.base.dn";
 
 
     /** The key of the configuration. e.g. groupOfNames */
     /** The key of the configuration. e.g. groupOfNames */
     String LDAP_ADMIN_ROLE_OBJECT_CLASSES = "ldap.admin.role.object.classes";
     String LDAP_ADMIN_ROLE_OBJECT_CLASSES = "ldap.admin.role.object.classes";
 
 
-    /** The key of the configuration. e.g. cn=%s,ou=Group,dc=fess,dc=codelibs,dc=org */
-    String LDAP_ADMIN_GROUP_SECURITY_PRINCIPAL = "ldap.admin.group.security.principal";
+    /** The key of the configuration. e.g. cn=%s */
+    String LDAP_ADMIN_GROUP_FILTER = "ldap.admin.group.filter";
+
+    /** The key of the configuration. e.g. ou=Group,dc=fess,dc=codelibs,dc=org */
+    String LDAP_ADMIN_GROUP_BASE_DN = "ldap.admin.group.base.dn";
 
 
     /** The key of the configuration. e.g. groupOfNames */
     /** The key of the configuration. e.g. groupOfNames */
     String LDAP_ADMIN_GROUP_OBJECT_CLASSES = "ldap.admin.group.object.classes";
     String LDAP_ADMIN_GROUP_OBJECT_CLASSES = "ldap.admin.group.object.classes";
 
 
+    /** The key of the configuration. e.g. memberOf */
+    String LDAP_MEMBEROF_ATTRIBUTE = "ldap.memberof.attribute";
+
+    /** The key of the configuration. e.g. true */
+    String LDAP_ROLE_SEARCH_USER_ENABLED = "ldap.role.search.user.enabled";
+
+    /** The key of the configuration. e.g. true */
+    String LDAP_ROLE_SEARCH_GROUP_ENABLED = "ldap.role.search.group.enabled";
+
+    /** The key of the configuration. e.g. true */
+    String LDAP_ROLE_SEARCH_ROLE_ENABLED = "ldap.role.search.role.enabled";
+
+    /** The key of the configuration. e.g. 1 */
+    String LDAP_ROLE_SEARCH_USER_PREFIX = "ldap.role.search.user.prefix";
+
+    /** The key of the configuration. e.g. 2 */
+    String LDAP_ROLE_SEARCH_GROUP_PREFIX = "ldap.role.search.group.prefix";
+
+    /** The key of the configuration. e.g. R */
+    String LDAP_ROLE_SEARCH_ROLE_PREFIX = "ldap.role.search.role.prefix";
+
     /**
     /**
      * Get the value of property as {@link String}.
      * Get the value of property as {@link String}.
      * @param propertyKey The key of the property. (NotNull)
      * @param propertyKey The key of the property. (NotNull)
@@ -1675,34 +1699,6 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
      */
      */
     boolean isSmbRoleFromFile();
     boolean isSmbRoleFromFile();
 
 
-    /**
-     * Get the value for the key 'smb.role.as.user'. <br>
-     * The value is, e.g. true <br>
-     * @return The value of found property. (NotNull: if not found, exception but basically no way)
-     */
-    String getSmbRoleAsUser();
-
-    /**
-     * Is the property for the key 'smb.role.as.user' true? <br>
-     * The value is, e.g. true <br>
-     * @return The determination, true or false. (if not found, exception but basically no way)
-     */
-    boolean isSmbRoleAsUser();
-
-    /**
-     * Get the value for the key 'smb.role.as.group'. <br>
-     * The value is, e.g. true <br>
-     * @return The value of found property. (NotNull: if not found, exception but basically no way)
-     */
-    String getSmbRoleAsGroup();
-
-    /**
-     * Is the property for the key 'smb.role.as.group' true? <br>
-     * The value is, e.g. true <br>
-     * @return The determination, true or false. (if not found, exception but basically no way)
-     */
-    boolean isSmbRoleAsGroup();
-
     /**
     /**
      * Get the value for the key 'smb.available.sid.types'. <br>
      * Get the value for the key 'smb.available.sid.types'. <br>
      * The value is, e.g. 1,2 <br>
      * The value is, e.g. 1,2 <br>
@@ -2542,11 +2538,18 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     String getLdapAdminSecurityCredentials();
     String getLdapAdminSecurityCredentials();
 
 
     /**
     /**
-     * Get the value for the key 'ldap.admin.user.security.principal'. <br>
-     * The value is, e.g. uid=%s,ou=People,dc=fess,dc=codelibs,dc=org <br>
+     * Get the value for the key 'ldap.admin.user.filter'. <br>
+     * The value is, e.g. uid=%s <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapAdminUserFilter();
+
+    /**
+     * Get the value for the key 'ldap.admin.user.base.dn'. <br>
+     * The value is, e.g. ou=People,dc=fess,dc=codelibs,dc=org <br>
      * @return The value of found property. (NotNull: if not found, exception but basically no way)
      * @return The value of found property. (NotNull: if not found, exception but basically no way)
      */
      */
-    String getLdapAdminUserSecurityPrincipal();
+    String getLdapAdminUserBaseDn();
 
 
     /**
     /**
      * Get the value for the key 'ldap.admin.user.object.classes'. <br>
      * Get the value for the key 'ldap.admin.user.object.classes'. <br>
@@ -2556,11 +2559,18 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     String getLdapAdminUserObjectClasses();
     String getLdapAdminUserObjectClasses();
 
 
     /**
     /**
-     * Get the value for the key 'ldap.admin.role.security.principal'. <br>
-     * The value is, e.g. cn=%s,ou=Role,dc=fess,dc=codelibs,dc=org <br>
+     * Get the value for the key 'ldap.admin.role.filter'. <br>
+     * The value is, e.g. cn=%s <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapAdminRoleFilter();
+
+    /**
+     * Get the value for the key 'ldap.admin.role.base.dn'. <br>
+     * The value is, e.g. ou=Role,dc=fess,dc=codelibs,dc=org <br>
      * @return The value of found property. (NotNull: if not found, exception but basically no way)
      * @return The value of found property. (NotNull: if not found, exception but basically no way)
      */
      */
-    String getLdapAdminRoleSecurityPrincipal();
+    String getLdapAdminRoleBaseDn();
 
 
     /**
     /**
      * Get the value for the key 'ldap.admin.role.object.classes'. <br>
      * Get the value for the key 'ldap.admin.role.object.classes'. <br>
@@ -2570,11 +2580,18 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     String getLdapAdminRoleObjectClasses();
     String getLdapAdminRoleObjectClasses();
 
 
     /**
     /**
-     * Get the value for the key 'ldap.admin.group.security.principal'. <br>
-     * The value is, e.g. cn=%s,ou=Group,dc=fess,dc=codelibs,dc=org <br>
+     * Get the value for the key 'ldap.admin.group.filter'. <br>
+     * The value is, e.g. cn=%s <br>
      * @return The value of found property. (NotNull: if not found, exception but basically no way)
      * @return The value of found property. (NotNull: if not found, exception but basically no way)
      */
      */
-    String getLdapAdminGroupSecurityPrincipal();
+    String getLdapAdminGroupFilter();
+
+    /**
+     * Get the value for the key 'ldap.admin.group.base.dn'. <br>
+     * The value is, e.g. ou=Group,dc=fess,dc=codelibs,dc=org <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapAdminGroupBaseDn();
 
 
     /**
     /**
      * Get the value for the key 'ldap.admin.group.object.classes'. <br>
      * Get the value for the key 'ldap.admin.group.object.classes'. <br>
@@ -2583,6 +2600,92 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
      */
      */
     String getLdapAdminGroupObjectClasses();
     String getLdapAdminGroupObjectClasses();
 
 
+    /**
+     * Get the value for the key 'ldap.memberof.attribute'. <br>
+     * The value is, e.g. memberOf <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapMemberofAttribute();
+
+    /**
+     * Get the value for the key 'ldap.role.search.user.enabled'. <br>
+     * The value is, e.g. true <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapRoleSearchUserEnabled();
+
+    /**
+     * Is the property for the key 'ldap.role.search.user.enabled' true? <br>
+     * The value is, e.g. true <br>
+     * @return The determination, true or false. (if not found, exception but basically no way)
+     */
+    boolean isLdapRoleSearchUserEnabled();
+
+    /**
+     * Get the value for the key 'ldap.role.search.group.enabled'. <br>
+     * The value is, e.g. true <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapRoleSearchGroupEnabled();
+
+    /**
+     * Is the property for the key 'ldap.role.search.group.enabled' true? <br>
+     * The value is, e.g. true <br>
+     * @return The determination, true or false. (if not found, exception but basically no way)
+     */
+    boolean isLdapRoleSearchGroupEnabled();
+
+    /**
+     * Get the value for the key 'ldap.role.search.role.enabled'. <br>
+     * The value is, e.g. true <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapRoleSearchRoleEnabled();
+
+    /**
+     * Is the property for the key 'ldap.role.search.role.enabled' true? <br>
+     * The value is, e.g. true <br>
+     * @return The determination, true or false. (if not found, exception but basically no way)
+     */
+    boolean isLdapRoleSearchRoleEnabled();
+
+    /**
+     * Get the value for the key 'ldap.role.search.user.prefix'. <br>
+     * The value is, e.g. 1 <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapRoleSearchUserPrefix();
+
+    /**
+     * Get the value for the key 'ldap.role.search.user.prefix' as {@link Integer}. <br>
+     * The value is, e.g. 1 <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     * @throws NumberFormatException When the property is not integer.
+     */
+    Integer getLdapRoleSearchUserPrefixAsInteger();
+
+    /**
+     * Get the value for the key 'ldap.role.search.group.prefix'. <br>
+     * The value is, e.g. 2 <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapRoleSearchGroupPrefix();
+
+    /**
+     * Get the value for the key 'ldap.role.search.group.prefix' as {@link Integer}. <br>
+     * The value is, e.g. 2 <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     * @throws NumberFormatException When the property is not integer.
+     */
+    Integer getLdapRoleSearchGroupPrefixAsInteger();
+
+    /**
+     * Get the value for the key 'ldap.role.search.role.prefix'. <br>
+     * The value is, e.g. R <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapRoleSearchRolePrefix();
+
     /**
     /**
      * The simple implementation for configuration.
      * The simple implementation for configuration.
      * @author FreeGen
      * @author FreeGen
@@ -3104,22 +3207,6 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
             return is(FessConfig.SMB_ROLE_FROM_FILE);
             return is(FessConfig.SMB_ROLE_FROM_FILE);
         }
         }
 
 
-        public String getSmbRoleAsUser() {
-            return get(FessConfig.SMB_ROLE_AS_USER);
-        }
-
-        public boolean isSmbRoleAsUser() {
-            return is(FessConfig.SMB_ROLE_AS_USER);
-        }
-
-        public String getSmbRoleAsGroup() {
-            return get(FessConfig.SMB_ROLE_AS_GROUP);
-        }
-
-        public boolean isSmbRoleAsGroup() {
-            return is(FessConfig.SMB_ROLE_AS_GROUP);
-        }
-
         public String getSmbAvailableSidTypes() {
         public String getSmbAvailableSidTypes() {
             return get(FessConfig.SMB_AVAILABLE_SID_TYPES);
             return get(FessConfig.SMB_AVAILABLE_SID_TYPES);
         }
         }
@@ -3568,28 +3655,88 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
             return get(FessConfig.LDAP_ADMIN_SECURITY_CREDENTIALS);
             return get(FessConfig.LDAP_ADMIN_SECURITY_CREDENTIALS);
         }
         }
 
 
-        public String getLdapAdminUserSecurityPrincipal() {
-            return get(FessConfig.LDAP_ADMIN_USER_SECURITY_PRINCIPAL);
+        public String getLdapAdminUserFilter() {
+            return get(FessConfig.LDAP_ADMIN_USER_FILTER);
+        }
+
+        public String getLdapAdminUserBaseDn() {
+            return get(FessConfig.LDAP_ADMIN_USER_BASE_DN);
         }
         }
 
 
         public String getLdapAdminUserObjectClasses() {
         public String getLdapAdminUserObjectClasses() {
             return get(FessConfig.LDAP_ADMIN_USER_OBJECT_CLASSES);
             return get(FessConfig.LDAP_ADMIN_USER_OBJECT_CLASSES);
         }
         }
 
 
-        public String getLdapAdminRoleSecurityPrincipal() {
-            return get(FessConfig.LDAP_ADMIN_ROLE_SECURITY_PRINCIPAL);
+        public String getLdapAdminRoleFilter() {
+            return get(FessConfig.LDAP_ADMIN_ROLE_FILTER);
+        }
+
+        public String getLdapAdminRoleBaseDn() {
+            return get(FessConfig.LDAP_ADMIN_ROLE_BASE_DN);
         }
         }
 
 
         public String getLdapAdminRoleObjectClasses() {
         public String getLdapAdminRoleObjectClasses() {
             return get(FessConfig.LDAP_ADMIN_ROLE_OBJECT_CLASSES);
             return get(FessConfig.LDAP_ADMIN_ROLE_OBJECT_CLASSES);
         }
         }
 
 
-        public String getLdapAdminGroupSecurityPrincipal() {
-            return get(FessConfig.LDAP_ADMIN_GROUP_SECURITY_PRINCIPAL);
+        public String getLdapAdminGroupFilter() {
+            return get(FessConfig.LDAP_ADMIN_GROUP_FILTER);
+        }
+
+        public String getLdapAdminGroupBaseDn() {
+            return get(FessConfig.LDAP_ADMIN_GROUP_BASE_DN);
         }
         }
 
 
         public String getLdapAdminGroupObjectClasses() {
         public String getLdapAdminGroupObjectClasses() {
             return get(FessConfig.LDAP_ADMIN_GROUP_OBJECT_CLASSES);
             return get(FessConfig.LDAP_ADMIN_GROUP_OBJECT_CLASSES);
         }
         }
+
+        public String getLdapMemberofAttribute() {
+            return get(FessConfig.LDAP_MEMBEROF_ATTRIBUTE);
+        }
+
+        public String getLdapRoleSearchUserEnabled() {
+            return get(FessConfig.LDAP_ROLE_SEARCH_USER_ENABLED);
+        }
+
+        public boolean isLdapRoleSearchUserEnabled() {
+            return is(FessConfig.LDAP_ROLE_SEARCH_USER_ENABLED);
+        }
+
+        public String getLdapRoleSearchGroupEnabled() {
+            return get(FessConfig.LDAP_ROLE_SEARCH_GROUP_ENABLED);
+        }
+
+        public boolean isLdapRoleSearchGroupEnabled() {
+            return is(FessConfig.LDAP_ROLE_SEARCH_GROUP_ENABLED);
+        }
+
+        public String getLdapRoleSearchRoleEnabled() {
+            return get(FessConfig.LDAP_ROLE_SEARCH_ROLE_ENABLED);
+        }
+
+        public boolean isLdapRoleSearchRoleEnabled() {
+            return is(FessConfig.LDAP_ROLE_SEARCH_ROLE_ENABLED);
+        }
+
+        public String getLdapRoleSearchUserPrefix() {
+            return get(FessConfig.LDAP_ROLE_SEARCH_USER_PREFIX);
+        }
+
+        public Integer getLdapRoleSearchUserPrefixAsInteger() {
+            return getAsInteger(FessConfig.LDAP_ROLE_SEARCH_USER_PREFIX);
+        }
+
+        public String getLdapRoleSearchGroupPrefix() {
+            return get(FessConfig.LDAP_ROLE_SEARCH_GROUP_PREFIX);
+        }
+
+        public Integer getLdapRoleSearchGroupPrefixAsInteger() {
+            return getAsInteger(FessConfig.LDAP_ROLE_SEARCH_GROUP_PREFIX);
+        }
+
+        public String getLdapRoleSearchRolePrefix() {
+            return get(FessConfig.LDAP_ROLE_SEARCH_ROLE_PREFIX);
+        }
     }
     }
 }
 }

+ 39 - 6
src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java

@@ -430,10 +430,21 @@ public interface FessProp {
         return oc;
         return oc;
     }
     }
 
 
-    String getLdapAdminUserSecurityPrincipal();
+    String getLdapAdminUserFilter();
+
+    public default String getLdapAdminUserFilter(final String name) {
+        return String.format(getLdapAdminUserFilter(), name);
+    }
+
+    String getLdapAdminUserBaseDn();
 
 
     public default String getLdapAdminUserSecurityPrincipal(final String name) {
     public default String getLdapAdminUserSecurityPrincipal(final String name) {
-        return String.format(getLdapAdminUserSecurityPrincipal(), name);
+        StringBuilder buf = new StringBuilder(100);
+        buf.append(String.format(getLdapAdminUserFilter(), name));
+        if (StringUtil.isNotBlank(getLdapAdminUserBaseDn())) {
+            buf.append(',').append(getLdapAdminUserBaseDn());
+        }
+        return buf.toString();
     }
     }
 
 
     String getLdapAdminRoleObjectClasses();
     String getLdapAdminRoleObjectClasses();
@@ -444,10 +455,21 @@ public interface FessProp {
         return oc;
         return oc;
     }
     }
 
 
-    String getLdapAdminRoleSecurityPrincipal();
+    String getLdapAdminRoleFilter();
+
+    public default String getLdapAdminRoleFilter(final String name) {
+        return String.format(getLdapAdminRoleFilter(), name);
+    }
+
+    String getLdapAdminRoleBaseDn();
 
 
     public default String getLdapAdminRoleSecurityPrincipal(final String name) {
     public default String getLdapAdminRoleSecurityPrincipal(final String name) {
-        return String.format(getLdapAdminRoleSecurityPrincipal(), name);
+        StringBuilder buf = new StringBuilder(100);
+        buf.append(String.format(getLdapAdminRoleFilter(), name));
+        if (StringUtil.isNotBlank(getLdapAdminRoleBaseDn())) {
+            buf.append(',').append(getLdapAdminRoleBaseDn());
+        }
+        return buf.toString();
     }
     }
 
 
     String getLdapAdminGroupObjectClasses();
     String getLdapAdminGroupObjectClasses();
@@ -458,9 +480,20 @@ public interface FessProp {
         return oc;
         return oc;
     }
     }
 
 
-    String getLdapAdminGroupSecurityPrincipal();
+    String getLdapAdminGroupFilter();
+
+    public default String getLdapAdminGroupFilter(final String name) {
+        return String.format(getLdapAdminGroupFilter(), name);
+    }
+
+    String getLdapAdminGroupBaseDn();
 
 
     public default String getLdapAdminGroupSecurityPrincipal(final String name) {
     public default String getLdapAdminGroupSecurityPrincipal(final String name) {
-        return String.format(getLdapAdminGroupSecurityPrincipal(), name);
+        StringBuilder buf = new StringBuilder(100);
+        buf.append(String.format(getLdapAdminGroupFilter(), name));
+        if (StringUtil.isNotBlank(getLdapAdminGroupBaseDn())) {
+            buf.append(',').append(getLdapAdminGroupBaseDn());
+        }
+        return buf.toString();
     }
     }
 }
 }

+ 1 - 1
src/main/resources/app.xml

@@ -146,7 +146,7 @@
 	</component>
 	</component>
 	<component name="popularWordHelper" class="org.codelibs.fess.helper.PopularWordHelper">
 	<component name="popularWordHelper" class="org.codelibs.fess.helper.PopularWordHelper">
 	</component>
 	</component>
-	<component name="userInfoHelper" class="org.codelibs.fess.helper.impl.CookieUserInfoHelperImpl">
+	<component name="userInfoHelper" class="org.codelibs.fess.helper.UserInfoHelper">
 	</component>
 	</component>
 	<component name="openSearchHelper" class="org.codelibs.fess.helper.OpenSearchHelper">
 	<component name="openSearchHelper" class="org.codelibs.fess.helper.OpenSearchHelper">
 		<property name="osddPath">"/WEB-INF/orig/open-search/osdd.xml"</property>
 		<property name="osddPath">"/WEB-INF/orig/open-search/osdd.xml"</property>

+ 1 - 1
src/main/resources/fess.xml

@@ -86,7 +86,7 @@
 	</component>
 	</component>
 	<component name="crawlingInfoHelper" class="org.codelibs.fess.helper.CrawlingInfoHelper">
 	<component name="crawlingInfoHelper" class="org.codelibs.fess.helper.CrawlingInfoHelper">
 	</component>
 	</component>
-	<component name="roleQueryHelper" class="org.codelibs.fess.helper.impl.RoleQueryHelperImpl">
+	<component name="roleQueryHelper" class="org.codelibs.fess.helper.RoleQueryHelper">
 		<!-- ex. parameter: fessRoles=123%0aadmin -->
 		<!-- ex. parameter: fessRoles=123%0aadmin -->
 		<!-- 
 		<!-- 
 		<property name="parameterKey">"fessRoles"</property>
 		<property name="parameterKey">"fessRoles"</property>

+ 15 - 5
src/main/resources/fess_config.properties

@@ -212,8 +212,6 @@ query.boost.content.lang=1.3
 
 
 # acl
 # acl
 smb.role.from.file=true
 smb.role.from.file=true
-smb.role.as.user=true
-smb.role.as.group=true
 smb.available.sid.types=1,2
 smb.available.sid.types=1,2
 
 
 # backup
 # backup
@@ -356,10 +354,22 @@ ldap.admin.security.authentication=simple
 ldap.admin.provider.url=ldap\://localhost\:1389
 ldap.admin.provider.url=ldap\://localhost\:1389
 ldap.admin.security.principal=cn\=Directory Manager
 ldap.admin.security.principal=cn\=Directory Manager
 ldap.admin.security.credentials=password
 ldap.admin.security.credentials=password
-ldap.admin.user.security.principal=uid\=%s,ou\=People,dc\=fess,dc\=codelibs,dc\=org
+ldap.admin.user.filter=uid\=%s
+ldap.admin.user.base.dn=ou\=People,dc\=fess,dc\=codelibs,dc\=org
 ldap.admin.user.object.classes=organizationalPerson,top,person,inetOrgPerson
 ldap.admin.user.object.classes=organizationalPerson,top,person,inetOrgPerson
-ldap.admin.role.security.principal=cn\=%s,ou\=Role,dc\=fess,dc\=codelibs,dc\=org
+ldap.admin.role.filter=cn\=%s
+ldap.admin.role.base.dn=ou\=Role,dc\=fess,dc\=codelibs,dc\=org
 ldap.admin.role.object.classes=groupOfNames
 ldap.admin.role.object.classes=groupOfNames
-ldap.admin.group.security.principal=cn\=%s,ou\=Group,dc\=fess,dc\=codelibs,dc\=org
+ldap.admin.group.filter=cn\=%s
+ldap.admin.group.base.dn=ou\=Group,dc\=fess,dc\=codelibs,dc\=org
 ldap.admin.group.object.classes=groupOfNames
 ldap.admin.group.object.classes=groupOfNames
 
 
+ldap.memberof.attribute=memberOf
+#ldap.memberof.attribute=isMemberOf
+
+ldap.role.search.user.enabled=true
+ldap.role.search.group.enabled=true
+ldap.role.search.role.enabled=true
+ldap.role.search.user.prefix=1
+ldap.role.search.group.prefix=2
+ldap.role.search.role.prefix=R

+ 9 - 9
src/test/java/org/codelibs/fess/helper/impl/RoleQueryHelperImplTest.java → src/test/java/org/codelibs/fess/helper/RoleQueryHelperTest.java

@@ -13,7 +13,7 @@
  * either express or implied. See the License for the specific language
  * either express or implied. See the License for the specific language
  * governing permissions and limitations under the License.
  * governing permissions and limitations under the License.
  */
  */
-package org.codelibs.fess.helper.impl;
+package org.codelibs.fess.helper;
 
 
 import java.util.Set;
 import java.util.Set;
 
 
@@ -23,20 +23,20 @@ import org.codelibs.core.crypto.CachedCipher;
 import org.codelibs.core.exception.IllegalBlockSizeRuntimeException;
 import org.codelibs.core.exception.IllegalBlockSizeRuntimeException;
 import org.codelibs.fess.unit.UnitFessTestCase;
 import org.codelibs.fess.unit.UnitFessTestCase;
 
 
-public class RoleQueryHelperImplTest extends UnitFessTestCase {
-    public RoleQueryHelperImpl roleQueryHelperImpl;
+public class RoleQueryHelperTest extends UnitFessTestCase {
+    public RoleQueryHelper roleQueryHelperImpl;
     public CachedCipher cipher;
     public CachedCipher cipher;
 
 
     @Override
     @Override
     public void setUp() throws Exception {
     public void setUp() throws Exception {
         super.setUp();
         super.setUp();
-        roleQueryHelperImpl = new RoleQueryHelperImpl();
+        roleQueryHelperImpl = new RoleQueryHelper();
         cipher = new CachedCipher();
         cipher = new CachedCipher();
         cipher.setKey("1234567890123456");
         cipher.setKey("1234567890123456");
     }
     }
 
 
     public void test_buildByParameter() {
     public void test_buildByParameter() {
-        final RoleQueryHelperImpl roleQueryHelperImpl = new RoleQueryHelperImpl();
+        final RoleQueryHelper roleQueryHelperImpl = new RoleQueryHelper();
 
 
         Set<String> roleSet;
         Set<String> roleSet;
 
 
@@ -92,7 +92,7 @@ public class RoleQueryHelperImplTest extends UnitFessTestCase {
     }
     }
 
 
     public void test_buildByHeader() {
     public void test_buildByHeader() {
-        final RoleQueryHelperImpl roleQueryHelperImpl = new RoleQueryHelperImpl();
+        final RoleQueryHelper roleQueryHelperImpl = new RoleQueryHelper();
 
 
         Set<String> roleSet;
         Set<String> roleSet;
 
 
@@ -152,7 +152,7 @@ public class RoleQueryHelperImplTest extends UnitFessTestCase {
     }
     }
 
 
     public void test_buildByCookie() {
     public void test_buildByCookie() {
-        final RoleQueryHelperImpl roleQueryHelperImpl = new RoleQueryHelperImpl();
+        final RoleQueryHelper roleQueryHelperImpl = new RoleQueryHelper();
 
 
         Set<String> roleSet;
         Set<String> roleSet;
         Cookie cookie;
         Cookie cookie;
@@ -224,7 +224,7 @@ public class RoleQueryHelperImplTest extends UnitFessTestCase {
 
 
     public void test_decodedRoleList() {
     public void test_decodedRoleList() {
 
 
-        final RoleQueryHelperImpl roleQueryHelperImpl = new RoleQueryHelperImpl();
+        final RoleQueryHelper roleQueryHelperImpl = new RoleQueryHelper();
 
 
         Set<String> roleSet;
         Set<String> roleSet;
         boolean encrypted;
         boolean encrypted;
@@ -289,7 +289,7 @@ public class RoleQueryHelperImplTest extends UnitFessTestCase {
 
 
     public void test_decodedRoleList_withCipher() {
     public void test_decodedRoleList_withCipher() {
 
 
-        final RoleQueryHelperImpl roleQueryHelperImpl = new RoleQueryHelperImpl();
+        final RoleQueryHelper roleQueryHelperImpl = new RoleQueryHelper();
         roleQueryHelperImpl.cipher = cipher;
         roleQueryHelperImpl.cipher = cipher;
 
 
         Set<String> roleSet;
         Set<String> roleSet;