diff --git a/pom.xml b/pom.xml index 0e864af5c..f9bbc4f77 100644 --- a/pom.xml +++ b/pom.xml @@ -494,6 +494,11 @@ jsonic 1.3.8 + + com.fasterxml.jackson.core + jackson-databind + 2.6.3 + diff --git a/src/main/java/org/codelibs/fess/Constants.java b/src/main/java/org/codelibs/fess/Constants.java index fa1e95b99..c953b8faf 100644 --- a/src/main/java/org/codelibs/fess/Constants.java +++ b/src/main/java/org/codelibs/fess/Constants.java @@ -328,4 +328,6 @@ public class Constants extends CoreLibConstants { public static final String ELASTICSEARCH_WEB_URL = "http://localhost:9201"; public static final String ES_API_ACCESS_TOKEN = "esApiAccessToken"; + + public static final String ADMIN_PACKAGE = "org.codelibs.fess.app.web.admin"; } diff --git a/src/main/java/org/codelibs/fess/app/web/admin/group/AdminGroupAction.java b/src/main/java/org/codelibs/fess/app/web/admin/group/AdminGroupAction.java index ec38319f3..09c5b2f8f 100644 --- a/src/main/java/org/codelibs/fess/app/web/admin/group/AdminGroupAction.java +++ b/src/main/java/org/codelibs/fess/app/web/admin/group/AdminGroupAction.java @@ -216,7 +216,10 @@ public class AdminGroupAction extends FessAdminAction { switch (form.crudMode) { case CrudMode.CREATE: if (form instanceof CreateForm) { - return OptionalEntity.of(new Group()); + return OptionalEntity.of(new Group()).map(entity -> { + entity.setId(Base64.getEncoder().encodeToString(form.name.getBytes(Constants.CHARSET_UTF_8))); + return entity; + }); } break; case CrudMode.EDIT: @@ -233,7 +236,6 @@ public class AdminGroupAction extends FessAdminAction { protected OptionalEntity createGroup(final CreateForm form) { return getEntity(form).map(entity -> { copyBeanToBean(form, entity, op -> op.exclude(Constants.COMMON_CONVERSION_RULE)); - entity.setId(Base64.getEncoder().encodeToString(entity.getName().getBytes(Constants.CHARSET_UTF_8))); return entity; }); } diff --git a/src/main/java/org/codelibs/fess/app/web/admin/role/AdminRoleAction.java b/src/main/java/org/codelibs/fess/app/web/admin/role/AdminRoleAction.java index 9f02a4954..55a63d9e8 100644 --- a/src/main/java/org/codelibs/fess/app/web/admin/role/AdminRoleAction.java +++ b/src/main/java/org/codelibs/fess/app/web/admin/role/AdminRoleAction.java @@ -216,7 +216,10 @@ public class AdminRoleAction extends FessAdminAction { switch (form.crudMode) { case CrudMode.CREATE: if (form instanceof CreateForm) { - return OptionalEntity.of(new Role()); + return OptionalEntity.of(new Role()).map(entity -> { + entity.setId(Base64.getEncoder().encodeToString(form.name.getBytes(Constants.CHARSET_UTF_8))); + return entity; + }); } break; case CrudMode.EDIT: @@ -233,7 +236,6 @@ public class AdminRoleAction extends FessAdminAction { protected OptionalEntity createRole(final CreateForm form) { return getEntity(form).map(entity -> { copyBeanToBean(form, entity, op -> op.exclude(Constants.COMMON_CONVERSION_RULE)); - entity.setId(Base64.getEncoder().encodeToString(entity.getName().getBytes(Constants.CHARSET_UTF_8))); return entity; }); } diff --git a/src/main/java/org/codelibs/fess/app/web/admin/user/AdminUserAction.java b/src/main/java/org/codelibs/fess/app/web/admin/user/AdminUserAction.java index 2a6d07038..45a93d883 100644 --- a/src/main/java/org/codelibs/fess/app/web/admin/user/AdminUserAction.java +++ b/src/main/java/org/codelibs/fess/app/web/admin/user/AdminUserAction.java @@ -31,6 +31,7 @@ import org.codelibs.fess.app.web.CrudMode; import org.codelibs.fess.app.web.base.FessAdminAction; import org.codelibs.fess.es.user.exentity.User; import org.codelibs.fess.helper.SystemHelper; +import org.codelibs.fess.lang3.ArrayUtils; import org.dbflute.optional.OptionalEntity; import org.dbflute.optional.OptionalThing; import org.lastaflute.web.Execute; @@ -202,6 +203,8 @@ public class AdminUserAction extends FessAdminAction { public HtmlResponse create(final CreateForm form) { verifyCrudMode(form.crudMode, CrudMode.CREATE); validate(form, messages -> {}, toEditHtml()); + verifyPassword(form); + storePassword(form); createUser(form).ifPresent(entity -> { userService.store(entity); saveInfo(messages -> messages.addSuccessCrudCreateCrudTable(GLOBAL)); @@ -215,7 +218,10 @@ public class AdminUserAction extends FessAdminAction { public HtmlResponse update(final EditForm form) { verifyCrudMode(form.crudMode, CrudMode.EDIT); validate(form, messages -> {}, toEditHtml()); - //verifyPassword(form); + verifyPassword(form); + if (StringUtil.isNotBlank(form.password)) { + storePassword(form); + } createUser(form).ifPresent(entity -> { userService.store(entity); saveInfo(messages -> messages.addSuccessCrudUpdateCrudTable(GLOBAL)); @@ -240,16 +246,14 @@ public class AdminUserAction extends FessAdminAction { } //=================================================================================== - // Assist Logic - // ============ + // Assist Logic + // ============ private OptionalEntity getEntity(final CreateForm form) { switch (form.crudMode) { case CrudMode.CREATE: if (form instanceof CreateForm) { return OptionalEntity.of(new User()).map(entity -> { - sessionManager.getAttribute(TEMPORARY_PASSWORD, String.class).ifPresent(password -> { - entity.setPassword(password); - }); + entity.setId(Base64.getEncoder().encodeToString(form.name.getBytes(Constants.CHARSET_UTF_8))); return entity; }); } @@ -267,8 +271,10 @@ public class AdminUserAction extends FessAdminAction { protected OptionalEntity createUser(final CreateForm form) { return getEntity(form).map(entity -> { - copyBeanToBean(form, entity, op -> op.exclude(Constants.COMMON_CONVERSION_RULE)); - entity.setId(Base64.getEncoder().encodeToString(entity.getName().getBytes(Constants.CHARSET_UTF_8))); + copyBeanToBean(form, entity, op -> op.exclude(ArrayUtils.addAll(Constants.COMMON_CONVERSION_RULE, "password"))); + sessionManager.getAttribute(TEMPORARY_PASSWORD, String.class).ifPresent(password -> { + entity.setPassword(password); + }); return entity; }); } @@ -294,11 +300,13 @@ public class AdminUserAction extends FessAdminAction { protected void verifyPassword(final CreateForm form) { if (form.crudMode == CrudMode.CREATE && StringUtil.isBlank(form.password)) { + form.confirmPassword = null; throwValidationError(messages -> { messages.addErrorsBlankPassword(GLOBAL); }, toEditHtml()); } if (form.password != null && !form.password.equals(form.confirmPassword)) { + form.confirmPassword = null; throwValidationError(messages -> { messages.addErrorsInvalidConfirmPassword(GLOBAL); }, toEditHtml()); diff --git a/src/main/java/org/codelibs/fess/app/web/base/FessAdminAction.java b/src/main/java/org/codelibs/fess/app/web/base/FessAdminAction.java index 724170278..89df647f9 100644 --- a/src/main/java/org/codelibs/fess/app/web/base/FessAdminAction.java +++ b/src/main/java/org/codelibs/fess/app/web/base/FessAdminAction.java @@ -21,12 +21,15 @@ import javax.servlet.ServletContext; import org.codelibs.core.beans.util.BeanUtil; import org.codelibs.core.beans.util.CopyOptions; +import org.codelibs.fess.exception.UserRoleLoginException; import org.codelibs.fess.mylasta.action.FessMessages; import org.dbflute.optional.OptionalThing; import org.lastaflute.di.util.LdiFileUtil; +import org.lastaflute.web.callback.ActionRuntime; import org.lastaflute.web.callback.TypicalEmbeddedKeySupplier; import org.lastaflute.web.callback.TypicalKey.TypicalSimpleEmbeddedKeySupplier; import org.lastaflute.web.login.LoginManager; +import org.lastaflute.web.response.ActionResponse; import org.lastaflute.web.util.LaServletContextUtil; import org.lastaflute.web.validation.VaMessenger; @@ -106,4 +109,17 @@ public abstract class FessAdminAction extends FessBaseAction { } }; } + + // =================================================================================== + // Hook + // ====== + @Override + public ActionResponse godHandPrologue(final ActionRuntime runtime) { + try { + return super.godHandPrologue(runtime); + } catch (UserRoleLoginException e) { + return redirect(e.getActionClass()); + } + } + } diff --git a/src/main/java/org/codelibs/fess/app/web/base/FessBaseAction.java b/src/main/java/org/codelibs/fess/app/web/base/FessBaseAction.java index ed2ca8003..0180d92e2 100644 --- a/src/main/java/org/codelibs/fess/app/web/base/FessBaseAction.java +++ b/src/main/java/org/codelibs/fess/app/web/base/FessBaseAction.java @@ -77,7 +77,7 @@ public abstract class FessBaseAction extends TypicalAction // has several interf // to suppress unexpected override by sub-class // you should remove the 'final' if you need to override this @Override - public final ActionResponse godHandPrologue(final ActionRuntime runtime) { + public ActionResponse godHandPrologue(final ActionRuntime runtime) { return super.godHandPrologue(runtime); } diff --git a/src/main/java/org/codelibs/fess/app/web/base/login/FessLoginAssist.java b/src/main/java/org/codelibs/fess/app/web/base/login/FessLoginAssist.java index 9a64a78e3..0635b6678 100644 --- a/src/main/java/org/codelibs/fess/app/web/base/login/FessLoginAssist.java +++ b/src/main/java/org/codelibs/fess/app/web/base/login/FessLoginAssist.java @@ -17,9 +17,12 @@ package org.codelibs.fess.app.web.base.login; import javax.annotation.Resource; +import org.codelibs.fess.Constants; +import org.codelibs.fess.app.web.RootAction; import org.codelibs.fess.app.web.login.LoginAction; import org.codelibs.fess.es.user.exbhv.UserBhv; import org.codelibs.fess.es.user.exentity.User; +import org.codelibs.fess.exception.UserRoleLoginException; import org.codelibs.fess.mylasta.action.FessUserBean; import org.codelibs.fess.mylasta.direction.FessConfig; import org.dbflute.optional.OptionalEntity; @@ -104,7 +107,13 @@ public class FessLoginAssist extends TypicalLoginAssist { + if (!user.hasRoles(fessConfig.getAuthenticationAdminRoles().split(","))) { + throw new UserRoleLoginException(RootAction.class); + } + }); + } } // =================================================================================== diff --git a/src/main/java/org/codelibs/fess/app/web/login/LoginAction.java b/src/main/java/org/codelibs/fess/app/web/login/LoginAction.java index 6064bbaf5..d6fbb9e74 100644 --- a/src/main/java/org/codelibs/fess/app/web/login/LoginAction.java +++ b/src/main/java/org/codelibs/fess/app/web/login/LoginAction.java @@ -18,6 +18,7 @@ package org.codelibs.fess.app.web.login; import org.codelibs.fess.app.web.admin.dashboard.AdminDashboardAction; import org.codelibs.fess.app.web.base.FessSearchAction; import org.lastaflute.web.Execute; +import org.lastaflute.web.login.exception.LoginFailureException; import org.lastaflute.web.response.HtmlResponse; public class LoginAction extends FessSearchAction { @@ -55,7 +56,15 @@ public class LoginAction extends FessSearchAction { }); final String email = form.username; final String password = form.password; - return fessLoginAssist.loginRedirect(email, password, op -> {}, () -> getHtmlResponse()); + form.clearSecurityInfo(); + try { + return fessLoginAssist.loginRedirect(email, password, op -> {}, () -> getHtmlResponse()); + } catch (LoginFailureException lfe) { + throwValidationError(messages -> messages.addErrorsLoginError(GLOBAL), () -> { + return asHtml(path_Login_IndexJsp); + }); + } + return redirect(getClass()); } } \ No newline at end of file diff --git a/src/main/java/org/codelibs/fess/es/client/FessEsClient.java b/src/main/java/org/codelibs/fess/es/client/FessEsClient.java index e5d3a814e..41e35355e 100644 --- a/src/main/java/org/codelibs/fess/es/client/FessEsClient.java +++ b/src/main/java/org/codelibs/fess/es/client/FessEsClient.java @@ -163,6 +163,8 @@ import org.elasticsearch.threadpool.ThreadPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.io.BaseEncoding; public class FessEsClient implements Client { @@ -396,21 +398,37 @@ public class FessEsClient implements Client { if (ResourceUtil.isExist(dataPath)) { try { final BulkRequestBuilder builder = client.prepareBulk(); - Arrays.stream(FileUtil.readUTF8(dataPath).split("\n")).reduce((prev, line) -> { - if (StringUtil.isBlank(prev)) { - if (line.startsWith("{\"index\":{")) { - return line; - } else if (line.startsWith("{\"update\":{")) { - return line; - } else if (line.startsWith("{\"delete\":{")) { + ObjectMapper mapper = new ObjectMapper(); + Arrays.stream(FileUtil.readUTF8(dataPath).split("\n")).reduce( + (prev, line) -> { + try { + if (StringUtil.isBlank(prev)) { + Map> result = + mapper.readValue(line, new TypeReference>>() { + }); + if (result.keySet().contains("index")) { + return line; + } else if (result.keySet().contains("update")) { + return line; + } else if (result.keySet().contains("delete")) { + return StringUtil.EMPTY; + } + } else { + Map> result = + mapper.readValue(prev, new TypeReference>>() { + }); + if (result.keySet().contains("index")) { + final IndexRequestBuilder requestBuilder = + client.prepareIndex(configIndex, configType, result.get("index").get("_id")) + .setSource(line); + builder.add(requestBuilder); + } + } + } catch (Exception e) { + logger.warn("Failed to parse " + dataPath.toString()); + } return StringUtil.EMPTY; - } - } else if (prev.startsWith("{\"index\":{")) { - final IndexRequestBuilder requestBuilder = client.prepareIndex(configIndex, configType).setSource(line); - builder.add(requestBuilder); - } - return StringUtil.EMPTY; - }); + }); final BulkResponse response = builder.execute().actionGet(); if (response.hasFailures()) { logger.warn("Failed to register " + dataPath.toString() + ": " + response.buildFailureMessage()); diff --git a/src/main/java/org/codelibs/fess/exception/UserRoleLoginException.java b/src/main/java/org/codelibs/fess/exception/UserRoleLoginException.java new file mode 100644 index 000000000..a3e1a1617 --- /dev/null +++ b/src/main/java/org/codelibs/fess/exception/UserRoleLoginException.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012-2015 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.exception; + +import org.codelibs.fess.app.web.RootAction; + +public class UserRoleLoginException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private Class actionClass; + + public UserRoleLoginException(Class actionClass) { + this.actionClass = actionClass; + } + + public Class getActionClass() { + return actionClass; + } + + @Override + public Throwable fillInStackTrace() { + return null; + } +} diff --git a/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java b/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java index 4abaec378..7764c8cc7 100644 --- a/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java +++ b/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java @@ -25,6 +25,9 @@ public interface FessConfig extends FessEnv { /** The key of the configuration. e.g. Fess */ String DOMAIN_TITLE = "domain.title"; + /** The key of the configuration. e.g. admin */ + String AUTHENTICATION_ADMIN_ROLES = "authentication.admin.roles"; + /** The key of the configuration. e.g. / */ String COOKIE_DEFAULT_PATH = "cookie.default.path"; @@ -76,6 +79,14 @@ public interface FessConfig extends FessEnv { */ String getDomainTitle(); + /** + * Get the value for the key 'authentication.admin.roles'.
+ * The value is, e.g. admin
+ * comment: ------ + * @return The value of found property. (NotNull: if not found, exception but basically no way) + */ + String getAuthenticationAdminRoles(); + /** * Get the value for the key 'cookie.default.path'.
* The value is, e.g. /
@@ -204,6 +215,10 @@ public interface FessConfig extends FessEnv { return get(FessConfig.DOMAIN_TITLE); } + public String getAuthenticationAdminRoles() { + return get(FessConfig.AUTHENTICATION_ADMIN_ROLES); + } + public String getCookieDefaultPath() { return get(FessConfig.COOKIE_DEFAULT_PATH); } diff --git a/src/main/resources/fess_config.properties b/src/main/resources/fess_config.properties index 9f39cf657..feec28f2a 100644 --- a/src/main/resources/fess_config.properties +++ b/src/main/resources/fess_config.properties @@ -17,6 +17,11 @@ domain.title = Fess # ======================================================================================== # Web # ===== +# ---------------------------------------------------------- +# Permission +# ------ +authentication.admin.roles=admin + # ---------------------------------------------------------- # Cookie # ------ @@ -51,3 +56,4 @@ paging.page.range.fill.limit = true mail.from.name = Administrator mail.from.address = root@localhost + diff --git a/src/main/resources/fess_indices/.fess_user/role.bulk b/src/main/resources/fess_indices/.fess_user/role.bulk index 72b534122..176d9ece3 100644 --- a/src/main/resources/fess_indices/.fess_user/role.bulk +++ b/src/main/resources/fess_indices/.fess_user/role.bulk @@ -1,2 +1,2 @@ {"index":{"_index":".fess_user","_type":"role","_id":"YWRtaW4="}} -{"name":"admin","id":"YWRtaW4="} +{"name":"admin"} diff --git a/src/main/resources/fess_indices/.fess_user/user.bulk b/src/main/resources/fess_indices/.fess_user/user.bulk index 5f8d1cec5..4b01251b0 100644 --- a/src/main/resources/fess_indices/.fess_user/user.bulk +++ b/src/main/resources/fess_indices/.fess_user/user.bulk @@ -1,2 +1,2 @@ {"index":{"_index":".fess_user","_type":"user","_id":"YWRtaW4="}} -{"password":"8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918","roles":["YWRtaW4="],"name":"admin","id":"YWRtaW4="} +{"password":"8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918","roles":["YWRtaW4="],"name":"admin"}