소스 검색

fix #459 : add sn and givenName

Shinsuke Sugaya 9 년 전
부모
커밋
e02edff3f9

+ 8 - 0
src/main/config/es/fess_user.json

@@ -29,6 +29,14 @@
             "type" : "string",
             "index" : "not_analyzed"
           },
+          "surname" : {
+            "type" : "string",
+            "index" : "not_analyzed"
+          },
+          "givenName" : {
+            "type" : "string",
+            "index" : "not_analyzed"
+          },
           "roles" : {
             "type" : "string",
             "index" : "not_analyzed"

+ 0 - 2
src/main/java/org/codelibs/fess/app/web/RootAction.java

@@ -15,8 +15,6 @@
  */
 package org.codelibs.fess.app.web;
 
-import org.codelibs.core.lang.StringUtil;
-import org.codelibs.fess.Constants;
 import org.codelibs.fess.app.web.base.FessSearchAction;
 import org.codelibs.fess.app.web.base.SearchForm;
 import org.codelibs.fess.util.RenderDataUtil;

+ 7 - 0
src/main/java/org/codelibs/fess/app/web/admin/user/CreateForm.java

@@ -43,6 +43,13 @@ public class CreateForm implements Serializable {
     @Size(max = 100)
     public String confirmPassword;
 
+    @Required
+    @Size(max = 1000)
+    public String surname;
+
+    @Size(max = 1000)
+    public String givenName;
+
     public String[] roles;
 
     public String[] groups;

+ 0 - 2
src/main/java/org/codelibs/fess/app/web/login/LoginAction.java

@@ -15,8 +15,6 @@
  */
 package org.codelibs.fess.app.web.login;
 
-import org.codelibs.core.lang.StringUtil;
-import org.codelibs.fess.Constants;
 import org.codelibs.fess.app.web.admin.dashboard.AdminDashboardAction;
 import org.codelibs.fess.app.web.base.FessSearchAction;
 import org.codelibs.fess.mylasta.action.FessUserBean;

+ 2 - 0
src/main/java/org/codelibs/fess/es/user/bsbhv/BsUserBhv.java

@@ -77,6 +77,8 @@ public abstract class BsUserBhv extends EsAbstractBehavior<User, UserCB> {
             result.setGroups(toStringArray(source.get("groups")));
             result.setName(DfTypeUtil.toString(source.get("name")));
             result.setPassword(DfTypeUtil.toString(source.get("password")));
+            result.setSurname(DfTypeUtil.toString(source.get("surname")));
+            result.setGivenName(DfTypeUtil.toString(source.get("givenName")));
             result.setRoles(toStringArray(source.get("roles")));
             return result;
         } catch (InstantiationException | IllegalAccessException e) {

+ 34 - 0
src/main/java/org/codelibs/fess/es/user/bsentity/BsUser.java

@@ -46,6 +46,12 @@ public class BsUser extends EsAbstractEntity {
     /** password */
     protected String password;
 
+    /** surname */
+    protected String surname;
+
+    /** givenName */
+    protected String givenName;
+
     /** roles */
     protected String[] roles;
 
@@ -79,6 +85,12 @@ public class BsUser extends EsAbstractEntity {
         if (password != null) {
             sourceMap.put("password", password);
         }
+        if (surname != null) {
+            sourceMap.put("surname", surname);
+        }
+        if (givenName != null) {
+            sourceMap.put("givenName", givenName);
+        }
         if (roles != null) {
             sourceMap.put("roles", roles);
         }
@@ -94,6 +106,8 @@ public class BsUser extends EsAbstractEntity {
         sb.append(dm).append(groups);
         sb.append(dm).append(name);
         sb.append(dm).append(password);
+        sb.append(dm).append(surname);
+        sb.append(dm).append(givenName);
         sb.append(dm).append(roles);
         if (sb.length() > dm.length()) {
             sb.delete(0, dm.length());
@@ -135,6 +149,26 @@ public class BsUser extends EsAbstractEntity {
         this.password = value;
     }
 
+    public String getSurname() {
+        checkSpecifiedProperty("surname");
+        return convertEmptyToNull(surname);
+    }
+
+    public void setSurname(String value) {
+        registerModifiedProperty("surname");
+        this.surname = value;
+    }
+
+    public String getGivenName() {
+        checkSpecifiedProperty("givenName");
+        return convertEmptyToNull(givenName);
+    }
+
+    public void setGivenName(String value) {
+        registerModifiedProperty("givenName");
+        this.givenName = value;
+    }
+
     public String[] getRoles() {
         checkSpecifiedProperty("roles");
         return roles;

+ 16 - 0
src/main/java/org/codelibs/fess/es/user/bsentity/dbmeta/UserDbm.java

@@ -82,6 +82,8 @@ public class UserDbm extends AbstractDBMeta {
         setupEpg(_epgMap, et -> ((User) et).getGroups(), (et, vl) -> ((User) et).setGroups((String[]) vl), "groups");
         setupEpg(_epgMap, et -> ((User) et).getName(), (et, vl) -> ((User) et).setName(DfTypeUtil.toString(vl)), "name");
         setupEpg(_epgMap, et -> ((User) et).getPassword(), (et, vl) -> ((User) et).setPassword(DfTypeUtil.toString(vl)), "password");
+        setupEpg(_epgMap, et -> ((User) et).getSurname(), (et, vl) -> ((User) et).setSurname(DfTypeUtil.toString(vl)), "surname");
+        setupEpg(_epgMap, et -> ((User) et).getGivenName(), (et, vl) -> ((User) et).setGivenName(DfTypeUtil.toString(vl)), "givenName");
         setupEpg(_epgMap, et -> ((User) et).getRoles(), (et, vl) -> ((User) et).setRoles((String[]) vl), "roles");
     }
 
@@ -125,6 +127,10 @@ public class UserDbm extends AbstractDBMeta {
             0, null, false, null, null, null, null, null, false);
     protected final ColumnInfo _columnPassword = cci("password", "password", null, null, String.class, "password", null, false, false,
             false, "String", 0, 0, null, false, null, null, null, null, null, false);
+    protected final ColumnInfo _columnSurname = cci("surname", "surname", null, null, String.class, "surname", null, false, false, false,
+            "String", 0, 0, null, false, null, null, null, null, null, false);
+    protected final ColumnInfo _columnGivenName = cci("givenName", "givenName", null, null, String.class, "givenName", null, false, false,
+            false, "String", 0, 0, null, false, null, null, null, null, null, false);
     protected final ColumnInfo _columnRoles = cci("roles", "roles", null, null, String[].class, "roles", null, false, false, false,
             "String", 0, 0, null, false, null, null, null, null, null, false);
 
@@ -140,6 +146,14 @@ public class UserDbm extends AbstractDBMeta {
         return _columnPassword;
     }
 
+    public ColumnInfo columnSurname() {
+        return _columnSurname;
+    }
+
+    public ColumnInfo columnGivenName() {
+        return _columnGivenName;
+    }
+
     public ColumnInfo columnRoles() {
         return _columnRoles;
     }
@@ -149,6 +163,8 @@ public class UserDbm extends AbstractDBMeta {
         ls.add(columnGroups());
         ls.add(columnName());
         ls.add(columnPassword());
+        ls.add(columnSurname());
+        ls.add(columnGivenName());
         ls.add(columnRoles());
         return ls;
     }

+ 8 - 0
src/main/java/org/codelibs/fess/es/user/cbean/bs/BsUserCB.java

@@ -170,6 +170,14 @@ public class BsUserCB extends EsAbstractConditionBean {
             doColumn("password");
         }
 
+        public void columnSurname() {
+            doColumn("surname");
+        }
+
+        public void columnGivenName() {
+            doColumn("givenName");
+        }
+
         public void columnRoles() {
             doColumn("roles");
         }

+ 332 - 0
src/main/java/org/codelibs/fess/es/user/cbean/cq/bs/BsUserCQ.java

@@ -673,6 +673,338 @@ public abstract class BsUserCQ extends EsAbstractConditionQuery {
         return this;
     }
 
+    public void setSurname_Equal(String surname) {
+        setSurname_Term(surname, null);
+    }
+
+    public void setSurname_Equal(String surname, ConditionOptionCall<TermQueryBuilder> opLambda) {
+        setSurname_Term(surname, opLambda);
+    }
+
+    public void setSurname_Term(String surname) {
+        setSurname_Term(surname, null);
+    }
+
+    public void setSurname_Term(String surname, ConditionOptionCall<TermQueryBuilder> opLambda) {
+        TermQueryBuilder builder = regTermQ("surname", surname);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSurname_NotEqual(String surname) {
+        setSurname_NotTerm(surname, null);
+    }
+
+    public void setSurname_NotEqual(String surname, ConditionOptionCall<NotQueryBuilder> opLambda) {
+        setSurname_NotTerm(surname, opLambda);
+    }
+
+    public void setSurname_NotTerm(String surname) {
+        setSurname_NotTerm(surname, null);
+    }
+
+    public void setSurname_NotTerm(String surname, ConditionOptionCall<NotQueryBuilder> opLambda) {
+        NotQueryBuilder builder = QueryBuilders.notQuery(regTermQ("surname", surname));
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSurname_Terms(Collection<String> surnameList) {
+        setSurname_Terms(surnameList, null);
+    }
+
+    public void setSurname_Terms(Collection<String> surnameList, ConditionOptionCall<TermsQueryBuilder> opLambda) {
+        TermsQueryBuilder builder = regTermsQ("surname", surnameList);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSurname_InScope(Collection<String> surnameList) {
+        setSurname_Terms(surnameList, null);
+    }
+
+    public void setSurname_InScope(Collection<String> surnameList, ConditionOptionCall<TermsQueryBuilder> opLambda) {
+        setSurname_Terms(surnameList, opLambda);
+    }
+
+    public void setSurname_Match(String surname) {
+        setSurname_Match(surname, null);
+    }
+
+    public void setSurname_Match(String surname, ConditionOptionCall<MatchQueryBuilder> opLambda) {
+        MatchQueryBuilder builder = regMatchQ("surname", surname);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSurname_MatchPhrase(String surname) {
+        setSurname_MatchPhrase(surname, null);
+    }
+
+    public void setSurname_MatchPhrase(String surname, ConditionOptionCall<MatchQueryBuilder> opLambda) {
+        MatchQueryBuilder builder = regMatchPhraseQ("surname", surname);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSurname_MatchPhrasePrefix(String surname) {
+        setSurname_MatchPhrasePrefix(surname, null);
+    }
+
+    public void setSurname_MatchPhrasePrefix(String surname, ConditionOptionCall<MatchQueryBuilder> opLambda) {
+        MatchQueryBuilder builder = regMatchPhrasePrefixQ("surname", surname);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSurname_Fuzzy(String surname) {
+        setSurname_Fuzzy(surname, null);
+    }
+
+    public void setSurname_Fuzzy(String surname, ConditionOptionCall<FuzzyQueryBuilder> opLambda) {
+        FuzzyQueryBuilder builder = regFuzzyQ("surname", surname);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSurname_Prefix(String surname) {
+        setSurname_Prefix(surname, null);
+    }
+
+    public void setSurname_Prefix(String surname, ConditionOptionCall<PrefixQueryBuilder> opLambda) {
+        PrefixQueryBuilder builder = regPrefixQ("surname", surname);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSurname_GreaterThan(String surname) {
+        setSurname_GreaterThan(surname, null);
+    }
+
+    public void setSurname_GreaterThan(String surname, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        RangeQueryBuilder builder = regRangeQ("surname", ConditionKey.CK_GREATER_THAN, surname);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSurname_LessThan(String surname) {
+        setSurname_LessThan(surname, null);
+    }
+
+    public void setSurname_LessThan(String surname, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        RangeQueryBuilder builder = regRangeQ("surname", ConditionKey.CK_LESS_THAN, surname);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSurname_GreaterEqual(String surname) {
+        setSurname_GreaterEqual(surname, null);
+    }
+
+    public void setSurname_GreaterEqual(String surname, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        RangeQueryBuilder builder = regRangeQ("surname", ConditionKey.CK_GREATER_EQUAL, surname);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSurname_LessEqual(String surname) {
+        setSurname_LessEqual(surname, null);
+    }
+
+    public void setSurname_LessEqual(String surname, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        RangeQueryBuilder builder = regRangeQ("surname", ConditionKey.CK_LESS_EQUAL, surname);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public BsUserCQ addOrderBy_Surname_Asc() {
+        regOBA("surname");
+        return this;
+    }
+
+    public BsUserCQ addOrderBy_Surname_Desc() {
+        regOBD("surname");
+        return this;
+    }
+
+    public void setGivenName_Equal(String givenName) {
+        setGivenName_Term(givenName, null);
+    }
+
+    public void setGivenName_Equal(String givenName, ConditionOptionCall<TermQueryBuilder> opLambda) {
+        setGivenName_Term(givenName, opLambda);
+    }
+
+    public void setGivenName_Term(String givenName) {
+        setGivenName_Term(givenName, null);
+    }
+
+    public void setGivenName_Term(String givenName, ConditionOptionCall<TermQueryBuilder> opLambda) {
+        TermQueryBuilder builder = regTermQ("givenName", givenName);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setGivenName_NotEqual(String givenName) {
+        setGivenName_NotTerm(givenName, null);
+    }
+
+    public void setGivenName_NotEqual(String givenName, ConditionOptionCall<NotQueryBuilder> opLambda) {
+        setGivenName_NotTerm(givenName, opLambda);
+    }
+
+    public void setGivenName_NotTerm(String givenName) {
+        setGivenName_NotTerm(givenName, null);
+    }
+
+    public void setGivenName_NotTerm(String givenName, ConditionOptionCall<NotQueryBuilder> opLambda) {
+        NotQueryBuilder builder = QueryBuilders.notQuery(regTermQ("givenName", givenName));
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setGivenName_Terms(Collection<String> givenNameList) {
+        setGivenName_Terms(givenNameList, null);
+    }
+
+    public void setGivenName_Terms(Collection<String> givenNameList, ConditionOptionCall<TermsQueryBuilder> opLambda) {
+        TermsQueryBuilder builder = regTermsQ("givenName", givenNameList);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setGivenName_InScope(Collection<String> givenNameList) {
+        setGivenName_Terms(givenNameList, null);
+    }
+
+    public void setGivenName_InScope(Collection<String> givenNameList, ConditionOptionCall<TermsQueryBuilder> opLambda) {
+        setGivenName_Terms(givenNameList, opLambda);
+    }
+
+    public void setGivenName_Match(String givenName) {
+        setGivenName_Match(givenName, null);
+    }
+
+    public void setGivenName_Match(String givenName, ConditionOptionCall<MatchQueryBuilder> opLambda) {
+        MatchQueryBuilder builder = regMatchQ("givenName", givenName);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setGivenName_MatchPhrase(String givenName) {
+        setGivenName_MatchPhrase(givenName, null);
+    }
+
+    public void setGivenName_MatchPhrase(String givenName, ConditionOptionCall<MatchQueryBuilder> opLambda) {
+        MatchQueryBuilder builder = regMatchPhraseQ("givenName", givenName);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setGivenName_MatchPhrasePrefix(String givenName) {
+        setGivenName_MatchPhrasePrefix(givenName, null);
+    }
+
+    public void setGivenName_MatchPhrasePrefix(String givenName, ConditionOptionCall<MatchQueryBuilder> opLambda) {
+        MatchQueryBuilder builder = regMatchPhrasePrefixQ("givenName", givenName);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setGivenName_Fuzzy(String givenName) {
+        setGivenName_Fuzzy(givenName, null);
+    }
+
+    public void setGivenName_Fuzzy(String givenName, ConditionOptionCall<FuzzyQueryBuilder> opLambda) {
+        FuzzyQueryBuilder builder = regFuzzyQ("givenName", givenName);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setGivenName_Prefix(String givenName) {
+        setGivenName_Prefix(givenName, null);
+    }
+
+    public void setGivenName_Prefix(String givenName, ConditionOptionCall<PrefixQueryBuilder> opLambda) {
+        PrefixQueryBuilder builder = regPrefixQ("givenName", givenName);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setGivenName_GreaterThan(String givenName) {
+        setGivenName_GreaterThan(givenName, null);
+    }
+
+    public void setGivenName_GreaterThan(String givenName, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        RangeQueryBuilder builder = regRangeQ("givenName", ConditionKey.CK_GREATER_THAN, givenName);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setGivenName_LessThan(String givenName) {
+        setGivenName_LessThan(givenName, null);
+    }
+
+    public void setGivenName_LessThan(String givenName, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        RangeQueryBuilder builder = regRangeQ("givenName", ConditionKey.CK_LESS_THAN, givenName);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setGivenName_GreaterEqual(String givenName) {
+        setGivenName_GreaterEqual(givenName, null);
+    }
+
+    public void setGivenName_GreaterEqual(String givenName, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        RangeQueryBuilder builder = regRangeQ("givenName", ConditionKey.CK_GREATER_EQUAL, givenName);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setGivenName_LessEqual(String givenName) {
+        setGivenName_LessEqual(givenName, null);
+    }
+
+    public void setGivenName_LessEqual(String givenName, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        RangeQueryBuilder builder = regRangeQ("givenName", ConditionKey.CK_LESS_EQUAL, givenName);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public BsUserCQ addOrderBy_GivenName_Asc() {
+        regOBA("givenName");
+        return this;
+    }
+
+    public BsUserCQ addOrderBy_GivenName_Desc() {
+        regOBD("givenName");
+        return this;
+    }
+
     public void setRoles_Equal(String roles) {
         setRoles_Term(roles, null);
     }

+ 59 - 8
src/main/java/org/codelibs/fess/ldap/LdapManager.java

@@ -16,6 +16,7 @@
 package org.codelibs.fess.ldap;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Locale;
@@ -45,6 +46,7 @@ import org.codelibs.fess.exception.LdapOperationException;
 import org.codelibs.fess.helper.SystemHelper;
 import org.codelibs.fess.mylasta.direction.FessConfig;
 import org.codelibs.fess.util.ComponentUtil;
+import org.codelibs.fess.util.OptionalUtil;
 import org.codelibs.fess.util.StreamUtil;
 import org.dbflute.optional.OptionalEntity;
 import org.slf4j.Logger;
@@ -176,6 +178,32 @@ public class LdapManager {
         }
     }
 
+    protected List<Object> getAttributeValueList(final NamingEnumeration<SearchResult> result, final String name) {
+        try {
+            while (result.hasMoreElements()) {
+                final SearchResult srcrslt = result.next();
+                final Attributes attrs = srcrslt.getAttributes();
+
+                final Attribute attr = attrs.get(name);
+                if (attr == null) {
+                    continue;
+                }
+
+                final List<Object> attrList = new ArrayList<>();
+                for (int i = 0; i < attr.size(); i++) {
+                    final Object attrValue = attr.get(i);
+                    if (attrValue != null) {
+                        attrList.add(attrValue);
+                    }
+                }
+                return attrList;
+            }
+            return Collections.emptyList();
+        } catch (NamingException e) {
+            throw new LdapOperationException("Failed to parse attribute values for " + name, e);
+        }
+    }
+
     public void insert(final User user) {
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
         if (!fessConfig.isLdapAdminEnabled()) {
@@ -190,11 +218,7 @@ public class LdapManager {
                 adminEnv,
                 result -> {
                     if (result.hasMore()) {
-                        if (user.getOriginalPassword() != null) {
-                            final List<ModificationItem> modifyList = new ArrayList<>();
-                            modifyReplaceEntry(modifyList, "userPassword", user.getOriginalPassword());
-                            modify(userDN, modifyList, adminEnv);
-                        }
+                        modifyUserAttributes(user, adminEnv, userDN, result, fessConfig);
 
                         final List<String> oldGroupList = new ArrayList<>();
                         final List<String> oldRoleList = new ArrayList<>();
@@ -208,7 +232,6 @@ public class LdapManager {
                                 oldRoleList.add(name);
                             }
                         });
-
                         final List<String> newGroupList = StreamUtil.of(user.getGroupNames()).collect(Collectors.toList());
                         StreamUtil.of(user.getGroupNames()).forEach(name -> {
                             if (oldGroupList.contains(name)) {
@@ -315,10 +338,38 @@ public class LdapManager {
 
     }
 
+    protected void modifyUserAttributes(final User user, final Supplier<Hashtable<String, String>> adminEnv, final String userDN,
+            final NamingEnumeration<SearchResult> result, final FessConfig fessConfig) {
+        final List<ModificationItem> modifyList = new ArrayList<>();
+        if (user.getOriginalPassword() != null) {
+            modifyReplaceEntry(modifyList, "userPassword", user.getOriginalPassword());
+        }
+
+        final String attrSurname = fessConfig.getLdapAttrSurname();
+        OptionalUtil
+                .ofNullable(user.getSurname())
+                .filter(s -> StringUtil.isNotBlank(s))
+                .ifPresent(s -> modifyReplaceEntry(modifyList, attrSurname, s))
+                .orElse(() -> getAttributeValueList(result, attrSurname).stream().forEach(
+                        v -> modifyDeleteEntry(modifyList, attrSurname, v)));
+        final String attrGivenName = fessConfig.getLdapAttrGivenName();
+        OptionalUtil
+                .ofNullable(user.getGivenName())
+                .filter(s -> StringUtil.isNotBlank(s))
+                .ifPresent(s -> modifyReplaceEntry(modifyList, attrGivenName, s))
+                .orElse(() -> getAttributeValueList(result, attrGivenName).stream().forEach(
+                        v -> modifyDeleteEntry(modifyList, attrGivenName, v)));
+        modify(userDN, modifyList, adminEnv);
+    }
+
     protected void addUserAttributes(final BasicAttributes entry, final User user, final FessConfig fessConfig) {
         entry.put(new BasicAttribute("cn", user.getName()));
-        entry.put(new BasicAttribute("sn", user.getName()));
         entry.put(new BasicAttribute("userPassword", user.getOriginalPassword()));
+
+        OptionalUtil.ofNullable(user.getSurname()).filter(s -> StringUtil.isNotBlank(s))
+                .ifPresent(s -> entry.put(new BasicAttribute(fessConfig.getLdapAttrSurname(), s)));
+        OptionalUtil.ofNullable(user.getGivenName()).filter(s -> StringUtil.isNotBlank(s))
+                .ifPresent(s -> entry.put(new BasicAttribute(fessConfig.getLdapAttrGivenName(), s)));
     }
 
     public void delete(final User user) {
@@ -516,7 +567,7 @@ public class LdapManager {
         modifyList.add(mod);
     }
 
-    protected void modifyDeleteEntry(final List<ModificationItem> modifyList, final String name, final String value) {
+    protected void modifyDeleteEntry(final List<ModificationItem> modifyList, final String name, final Object value) {
         final Attribute attr = new BasicAttribute(name, value);
         final ModificationItem mod = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attr);
         modifyList.add(mod);

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

@@ -2070,6 +2070,18 @@ public class FessLabels extends ActionMessages {
     /** The key of the message: The limit of a search time was exceeded. The partial result might be displayed. */
     public static final String LABELS_process_time_is_exceeded = "{labels.process_time_is_exceeded}";
 
+    /** The key of the message: First Name */
+    public static final String LABELS_user_given_name = "{labels.user_given_name}";
+
+    /** The key of the message: First Name */
+    public static final String LABELS_GIVEN_NAME = "{labels.givenName}";
+
+    /** The key of the message: Last Name */
+    public static final String LABELS_user_surname = "{labels.user_surname}";
+
+    /** The key of the message: Last Name */
+    public static final String LABELS_SURAME = "{labels.surame}";
+
     /**
      * Assert the property is not null.
      * @param property The value of the property. (NotNull)

+ 28 - 0
src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java

@@ -774,6 +774,12 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     /** The key of the configuration. e.g. R */
     String LDAP_ROLE_SEARCH_ROLE_PREFIX = "ldap.role.search.role.prefix";
 
+    /** The key of the configuration. e.g. sn */
+    String LDAP_ATTR_SURNAME = "ldap.attr.surname";
+
+    /** The key of the configuration. e.g. givenName */
+    String LDAP_ATTR_GIVEN_NAME = "ldap.attr.givenName";
+
     /**
      * Get the value of property as {@link String}.
      * @param propertyKey The key of the property. (NotNull)
@@ -3182,6 +3188,20 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
      */
     String getLdapRoleSearchRolePrefix();
 
+    /**
+     * Get the value for the key 'ldap.attr.surname'. <br>
+     * The value is, e.g. sn <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapAttrSurname();
+
+    /**
+     * Get the value for the key 'ldap.attr.givenName'. <br>
+     * The value is, e.g. givenName <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getLdapAttrGivenName();
+
     /**
      * The simple implementation for configuration.
      * @author FreeGen
@@ -4446,5 +4466,13 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
         public String getLdapRoleSearchRolePrefix() {
             return get(FessConfig.LDAP_ROLE_SEARCH_ROLE_PREFIX);
         }
+
+        public String getLdapAttrSurname() {
+            return get(FessConfig.LDAP_ATTR_SURNAME);
+        }
+
+        public String getLdapAttrGivenName() {
+            return get(FessConfig.LDAP_ATTR_GIVEN_NAME);
+        }
     }
 }

+ 26 - 0
src/main/java/org/codelibs/fess/util/OptionalUtil.java

@@ -0,0 +1,26 @@
+/*
+ * 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.util;
+
+import org.dbflute.optional.OptionalEntity;
+
+public class OptionalUtil {
+
+    public static <T> OptionalEntity<T> ofNullable(T entity) {
+        return OptionalEntity.ofNullable(entity, () -> {});
+    }
+
+}

+ 4 - 0
src/main/resources/fess_config.properties

@@ -412,3 +412,7 @@ ldap.role.search.role.enabled=true
 ldap.role.search.user.prefix=1
 ldap.role.search.group.prefix=2
 ldap.role.search.role.prefix=R
+
+ldap.attr.surname=sn
+ldap.attr.givenName=givenName
+

+ 8 - 0
src/main/resources/fess_indices/.fess_user/user.json

@@ -15,6 +15,14 @@
         "type": "string",
         "index": "not_analyzed"
       },
+      "surname": {
+        "type": "string",
+        "index": "not_analyzed"
+      },
+      "givenName": {
+        "type": "string",
+        "index": "not_analyzed"
+      },
       "groups": {
         "type": "string",
         "index": "not_analyzed"

+ 4 - 0
src/main/resources/fess_label.properties

@@ -680,3 +680,7 @@ labels.send_testmail=Send TestMail
 labels.backup_configuration=Back Up
 labels.backup_name=Name
 labels.process_time_is_exceeded=The limit of a search time was exceeded. The partial result might be displayed.
+labels.user_given_name=First Name
+labels.givenName=First Name
+labels.user_surname=Last Name
+labels.surame=Last Name

+ 4 - 0
src/main/resources/fess_label_en.properties

@@ -680,3 +680,7 @@ labels.send_testmail=Send TestMail
 labels.backup_configuration=Back Up
 labels.backup_name=Name
 labels.process_time_is_exceeded=The limit of a search time was exceeded. The partial result might be displayed.
+labels.user_given_name=First Name
+labels.givenName=First Name
+labels.user_surname=Last Name
+labels.surame=Last Name

+ 4 - 0
src/main/resources/fess_label_ja.properties

@@ -680,3 +680,7 @@ labels.send_testmail=\u30c6\u30b9\u30c8\u30e1\u30fc\u30eb\u306e\u9001\u4fe1
 labels.backup_configuration=\u30d0\u30c3\u30af\u30a2\u30c3\u30d7
 labels.backup_name=\u540d\u524d
 labels.process_time_is_exceeded=\u691c\u7d22\u5f85\u3061\u6642\u9593\u306e\u4e0a\u9650\u3092\u8d85\u3048\u307e\u3057\u305f\u3002\u8868\u793a\u3055\u308c\u305f\u7d50\u679c\u306f\u691c\u7d22\u7d50\u679c\u306e\u4e00\u90e8\u3067\u3042\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002
+labels.user_given_name=\u540d\u524d(\u540d)
+labels.givenName=\u540d\u524d(\u540d)
+labels.user_surname=\u540d\u524d(\u59d3)
+labels.surame=\u540d\u524d(\u59d3)

+ 8 - 0
src/main/webapp/WEB-INF/view/admin/user/admin_user_details.jsp

@@ -50,6 +50,14 @@
 												<th class="col-xs-2"><la:message key="labels.user_name" /></th>
 												<td>${f:h(name)}<la:hidden property="name" /></td>
 											</tr>
+											<tr>
+												<th class="col-xs-2"><la:message key="labels.user_surname" /></th>
+												<td>${f:h(surname)}<la:hidden property="surname" /></td>
+											</tr>
+											<tr>
+												<th class="col-xs-2"><la:message key="labels.user_given_name" /></th>
+												<td>${f:h(givenName)}<la:hidden property="givenName" /></td>
+											</tr>
 											<tr>
 												<th><la:message key="labels.roles" /></th>
 												<td><c:forEach var="rt" varStatus="s"

+ 16 - 0
src/main/webapp/WEB-INF/view/admin/user/admin_user_edit.jsp

@@ -73,6 +73,22 @@
 												styleClass="form-control" />
 										</div>
 									</div>
+									<div class="form-group">
+										<label for="name" class="col-sm-3 control-label"><la:message
+												key="labels.user_surname" /></label>
+										<div class="col-sm-9">
+											<la:errors property="surname" />
+											<la:text property="surname" styleClass="form-control" />
+										</div>
+									</div>
+									<div class="form-group">
+										<label for="name" class="col-sm-3 control-label"><la:message
+												key="labels.user_given_name" /></label>
+										<div class="col-sm-9">
+											<la:errors property="givenName" />
+											<la:text property="givenName" styleClass="form-control" />
+										</div>
+									</div>
 									<div class="form-group">
 										<label for="roles" class="col-sm-3 control-label"><la:message
 												key="labels.roles" /></label>