Sfoglia il codice sorgente

fix #2497 update admin password

Shinsuke Sugaya 4 anni fa
parent
commit
ba8848097e

+ 73 - 1
src/main/java/org/codelibs/fess/app/web/login/LoginAction.java

@@ -15,16 +15,38 @@
  */
 package org.codelibs.fess.app.web.login;
 
+import javax.annotation.Resource;
+import javax.servlet.http.HttpSession;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.codelibs.core.lang.StringUtil;
+import org.codelibs.fess.app.service.UserService;
 import org.codelibs.fess.app.web.base.FessLoginAction;
 import org.codelibs.fess.app.web.base.login.LocalUserCredential;
+import org.codelibs.fess.app.web.profile.ProfileAction;
+import org.codelibs.fess.mylasta.action.FessUserBean;
+import org.codelibs.fess.util.ComponentUtil;
 import org.codelibs.fess.util.RenderDataUtil;
+import org.dbflute.optional.OptionalEntity;
 import org.dbflute.optional.OptionalThing;
 import org.lastaflute.web.Execute;
 import org.lastaflute.web.login.exception.LoginFailureException;
 import org.lastaflute.web.response.HtmlResponse;
+import org.lastaflute.web.validation.VaErrorHook;
 
 public class LoginAction extends FessLoginAction {
 
+    private static final Logger logger = LogManager.getLogger(LoginAction.class);
+
+    private static final String INVALID_OLD_PASSWORD = "LoginAction.invalidOldPassword";
+
+    // ===================================================================================
+    // Attribute
+    //
+    @Resource
+    private UserService userService;
+
     // ===================================================================================
     //                                                                       Login Execute
     //                                                                      ==============
@@ -55,7 +77,11 @@ public class LoginAction extends FessLoginAction {
             return fessLoginAssist.loginRedirect(new LocalUserCredential(username, password), op -> {}, () -> {
                 activityHelper.login(getUserBean());
                 userInfoHelper.deleteUserCodeFromCookie(request);
-                return getHtmlResponse();
+                if (ComponentUtil.getFessConfig().isValidAdminPassword(password)) {
+                    return getHtmlResponse();
+                }
+                getSession().ifPresent(session -> session.setAttribute(INVALID_OLD_PASSWORD, password));
+                return asHtml(virtualHost(path_Login_NewpasswordJsp));
             });
         } catch (final LoginFailureException lfe) {
             activityHelper.loginFailure(OptionalThing.of(new LocalUserCredential(username, password)));
@@ -64,4 +90,50 @@ public class LoginAction extends FessLoginAction {
         return redirect(getClass());
     }
 
+    @Execute
+    public HtmlResponse changePassword(final PasswordForm form) {
+        final VaErrorHook toIndexPage = () -> {
+            form.clearSecurityInfo();
+            return getUserBean().map(u -> asHtml(virtualHost(path_Login_NewpasswordJsp)).useForm(PasswordForm.class))
+                    .orElseGet(() -> redirect(LoginAction.class));
+        };
+        validatePasswordForm(form, toIndexPage);
+        final String username = getUserBean().map(FessUserBean::getUserId).get();
+        try {
+            userService.changePassword(username, form.password);
+            saveInfo(messages -> messages.addSuccessChangedPassword(GLOBAL));
+        } catch (final Exception e) {
+            logger.warn("Failed to change newPassword for " + username, e);
+            throwValidationError(messages -> messages.addErrorsFailedToChangePassword(GLOBAL), toIndexPage);
+        }
+        getSession().ifPresent(session -> session.removeAttribute(INVALID_OLD_PASSWORD));
+        return redirect(ProfileAction.class);
+    }
+
+    private void validatePasswordForm(final PasswordForm form, final VaErrorHook validationErrorLambda) {
+        validate(form, messages -> {}, validationErrorLambda);
+
+        if (!form.password.equals(form.confirmPassword)) {
+            throwValidationError(messages -> {
+                messages.addErrorsInvalidConfirmPassword(GLOBAL);
+            }, validationErrorLambda);
+        }
+
+        final String oldPassword =
+                getSession().map(session -> (String) session.getAttribute(INVALID_OLD_PASSWORD)).orElse(StringUtil.EMPTY);
+        fessLoginAssist.findLoginUser(new LocalUserCredential(getUserBean().get().getUserId(), oldPassword)).orElseGet(() -> {
+            throwValidationError(messages -> {
+                messages.addErrorsNoUserForChangingPassword(GLOBAL);
+            }, validationErrorLambda);
+            return null;
+        });
+    }
+
+    private OptionalThing<HttpSession> getSession() {
+        final HttpSession session = request.getSession(false);
+        if (session != null) {
+            return OptionalEntity.of(session);
+        }
+        return OptionalEntity.empty();
+    }
 }

+ 3 - 0
src/main/java/org/codelibs/fess/app/web/login/LoginForm.java

@@ -25,8 +25,11 @@ public class LoginForm {
     @NotBlank
     public String password;
 
+    public String confirmPassword;
+
     public void clearSecurityInfo() {
         password = null;
+        confirmPassword = null;
     }
 
 }

+ 35 - 0
src/main/java/org/codelibs/fess/app/web/login/PasswordForm.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012-2020 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.app.web.login;
+
+import javax.validation.constraints.NotBlank;
+
+public class PasswordForm {
+
+    public String username;
+
+    @NotBlank
+    public String password;
+
+    @NotBlank
+    public String confirmPassword;
+
+    public void clearSecurityInfo() {
+        password = null;
+        confirmPassword = null;
+    }
+
+}

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

@@ -433,6 +433,9 @@ public interface FessHtmlPath {
     /** The path of the HTML: /login/index.jsp */
     HtmlNext path_Login_IndexJsp = new HtmlNext("/login/index.jsp");
 
+    /** The path of the HTML: /login/newpassword.jsp */
+    HtmlNext path_Login_NewpasswordJsp = new HtmlNext("/login/newpassword.jsp");
+
     /** The path of the HTML: /profile/index.jsp */
     HtmlNext path_Profile_IndexJsp = new HtmlNext("/profile/index.jsp");
 

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

@@ -3159,6 +3159,18 @@ public class FessLabels extends UserMessages {
     /** The key of the message: Download */
     public static final String LABELS_storage_button_download = "{labels.storage_button_download}";
 
+    /** The key of the message: Your password needs to be updated. */
+    public static final String LABELS_LOGIN_NEWPASSWORD = "{labels.login.newpassword}";
+
+    /** The key of the message: New Password */
+    public static final String LABELS_LOGIN_placeholder_new_password = "{labels.login.placeholder_new_password}";
+
+    /** The key of the message: Confirm New Password */
+    public static final String LABELS_LOGIN_placeholder_confirm_new_password = "{labels.login.placeholder_confirm_new_password}";
+
+    /** The key of the message: Update */
+    public static final String LABELS_LOGIN_UPDATE = "{labels.login.update}";
+
     /**
      * Assert the property is not null.
      * @param property The value of the property. (NotNull)

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

@@ -1601,6 +1601,9 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     /** The key of the configuration. e.g. 1000 */
     String STORAGE_MAX_ITEMS_IN_PAGE = "storage.max.items.in.page";
 
+    /** The key of the configuration. e.g. admin */
+    String PASSWORD_INVALID_ADMIN_PASSWORDS = "password.invalid.admin.passwords";
+
     /**
      * Get the value of property as {@link String}.
      * @param propertyKey The key of the property. (NotNull)
@@ -6601,6 +6604,14 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
      */
     Integer getStorageMaxItemsInPageAsInteger();
 
+    /**
+     * Get the value for the key 'password.invalid.admin.passwords'. <br>
+     * The value is, e.g. admin <br>
+     * comment: ------
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getPasswordInvalidAdminPasswords();
+
     /**
      * The simple implementation for configuration.
      * @author FreeGen
@@ -9210,6 +9221,10 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
             return getAsInteger(FessConfig.STORAGE_MAX_ITEMS_IN_PAGE);
         }
 
+        public String getPasswordInvalidAdminPasswords() {
+            return get(FessConfig.PASSWORD_INVALID_ADMIN_PASSWORDS);
+        }
+
         @Override
         protected java.util.Map<String, String> prepareGeneratedDefaultMap() {
             java.util.Map<String, String> defaultMap = super.prepareGeneratedDefaultMap();
@@ -9679,6 +9694,7 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
                     "https://repo.maven.apache.org/maven2/org/codelibs/fess/,https://fess.codelibs.org/plugin/artifacts.yaml");
             defaultMap.put(FessConfig.PLUGIN_VERSION_FILTER, "");
             defaultMap.put(FessConfig.STORAGE_MAX_ITEMS_IN_PAGE, "1000");
+            defaultMap.put(FessConfig.PASSWORD_INVALID_ADMIN_PASSWORDS, "admin");
             defaultMap.put(FessConfig.lasta_di_SMART_DEPLOY_MODE, "hot");
             defaultMap.put(FessConfig.DEVELOPMENT_HERE, "true");
             defaultMap.put(FessConfig.ENVIRONMENT_TITLE, "Local Development");

+ 7 - 0
src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java

@@ -2067,4 +2067,11 @@ public interface FessProp {
         final String value = getHttpFileuploadThresholdSize();
         return value != null ? DfTypeUtil.toLong(value) : null;
     }
+
+    String getPasswordInvalidAdminPasswords();
+
+    default boolean isValidAdminPassword(final String password) {
+        return !split(getPasswordInvalidAdminPasswords(), "\n")
+                .get(stream -> stream.map(String::trim).filter(StringUtil::isNotEmpty).anyMatch(s -> s.equals(password)));
+    }
 }

+ 7 - 1
src/main/resources/fess_config.properties

@@ -554,7 +554,7 @@ index.backup.log.targets=click_log.ndjson,favorite_log.ndjson,search_log.ndjson,
 # logging
 logging.search.docs.enabled=true
 logging.search.docs.fields=filetype,created,click_count,title,doc_id,url,score,site,filename,host,digest,boost,mimetype,favorite_count,_id,lang,last_modified,content_length,timestamp
-logging.search.use.logfile=false
+logging.search.use.logfile=true
 logging.app.packages=org.codelibs,org.dbflute,org.lastaflute
 
 # ========================================================================================
@@ -837,3 +837,9 @@ plugin.version.filter=
 #                                                     ------
 storage.max.items.in.page=1000
 
+
+# ----------------------------------------------------------
+#                                                   Password
+#                                                     ------
+password.invalid.admin.passwords=\
+admin

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

@@ -1044,3 +1044,7 @@ labels.storage_bucket_name=Bucket Name
 labels.storage_file=File
 labels.storage_folder_name=Folder Name
 labels.storage_button_download=Download
+labels.login.newpassword=Your password needs to be updated.
+labels.login.placeholder_new_password=New Password
+labels.login.placeholder_confirm_new_password=Confirm New Password
+labels.login.update=Update

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

@@ -1044,3 +1044,7 @@ labels.storage_bucket_name=Bucket Name
 labels.storage_file=File
 labels.storage_folder_name=Folder Name
 labels.storage_button_download=Download
+labels.login.newpassword=Your password needs to be updated.
+labels.login.placeholder_new_password=New Password
+labels.login.placeholder_confirm_new_password=Confirm New Password
+labels.login.update=Update

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

@@ -1044,3 +1044,7 @@ labels.storage_bucket_name=バケット名
 labels.storage_file=ファイル
 labels.storage_folder_name=フォルダ名
 labels.storage_button_download=ダウンロード
+labels.login.newpassword=パスワードを更新する必要があります
+labels.login.placeholder_new_password=新しいパスワード
+labels.login.placeholder_confirm_new_password=新しいパスワードの確認
+labels.login.update=更新

+ 1 - 1
src/main/webapp/WEB-INF/view/login/index.jsp

@@ -35,7 +35,7 @@
 					</la:info>
 					<la:errors />
 				</div>
-				<la:form styleId="/login" method="post">
+				<la:form styleId="login" method="post">
 					<div class="input-group mb-3">
 						<c:set var="ph_username">
 							<la:message key="labels.login.placeholder_username" />

+ 81 - 0
src/main/webapp/WEB-INF/view/login/newpassword.jsp

@@ -0,0 +1,81 @@
+<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%><!DOCTYPE html>
+<html>
+<head profile="http://a9.com/-/spec/opensearch/1.1/">
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<title><la:message key="labels.login.title" /></title>
+<link href="${fe:url('/css/admin/bootstrap.min.css')}" rel="stylesheet" type="text/css" />
+<link href="${fe:url('/css/admin/font-awesome.min.css')}" rel="stylesheet" type="text/css" />
+<link href="${fe:url('/css/admin/adminlte.min.css')}" rel="stylesheet" type="text/css" />
+<link href="${fe:url('/css/admin/style.css')}" rel="stylesheet" type="text/css" />
+<!--[if lt IE 9]>
+<script src="${fe:url('/css/admin/html5shiv.min.js')}"></script>
+<script src="${fe:url('/css/admin/respond.min.js')}"></script>
+<![endif]-->
+</head>
+<body class="hold-transition login-page">
+	<div class="login-box">
+		<div class="login-logo">
+			<la:link href="/">
+				<img src="${fe:url('/images/logo-top.png')}"
+					alt="<la:message key="labels.header_brand_name" />" />
+			</la:link>
+		</div>
+		<div class="card">
+			<div class="card-body login-card-body">
+				<p class="login-box-msg">
+					<la:message key="labels.login.newpassword" />
+				</p>
+				<%-- Message --%>
+				<div>
+					<la:info id="msg" message="false">
+						<div class="alert alert-info">${msg}</div>
+					</la:info>
+					<la:errors />
+				</div>
+				<la:form styleId="newPassword" method="post">
+					<div class="input-group mb-3">
+						<c:set var="ph_new_password">
+							<la:message key="labels.login.placeholder_new_password" />
+						</c:set>
+						<la:password property="password" class="form-control"
+							placeholder="${ph_new_password}" />
+						<div class="input-group-append">
+							<span class="input-group-text">
+								<em class="fa fa-lock fa-fw"></em>
+							</span>
+						</div>
+					</div>
+					<div class="input-group mb-3">
+						<c:set var="ph_confirm_password">
+							<la:message key="labels.login.placeholder_confirm_new_password" />
+						</c:set>
+						<la:password property="confirmPassword" class="form-control"
+							placeholder="${ph_confirm_password}" />
+						<div class="input-group-append">
+							<span class="input-group-text">
+								<em class="fa fa-lock fa-fw"></em>
+							</span>
+						</div>
+					</div>
+					<div class="text-center">
+						<button type="submit" name="changePassword"
+							class="btn btn-primary btn-block"
+							value="<la:message key="labels.login.update"/>">
+							<em class="fa fa-pencil-alt"></em>
+							<la:message key="labels.login.update" />
+						</button>
+					</div>
+				</la:form>
+			</div>
+		</div>
+	</div>
+	<input type="hidden" id="contextPath" value="${contextPath}" />
+	<script type="text/javascript" src="${fe:url('/js/admin/popper.min.js')}"></script>
+	<script type="text/javascript"
+		src="${fe:url('/js/admin/jquery-3.4.1.min.js')}"></script>
+	<script type="text/javascript" src="${fe:url('/js/admin/bootstrap.min.js')}"></script>
+	<script type="text/javascript" src="${fe:url('/js/login.js')}"></script>
+</body>
+</html>

+ 2 - 2
src/main/webapp/WEB-INF/view/profile/index.jsp

@@ -34,7 +34,7 @@
 					</la:info>
 					<la:errors />
 				</div>
-				<la:form styleId="/login" method="post">
+				<la:form styleId="updatePassword" method="post">
 					<div class="input-group mb-3">
 						<c:set var="ph_old_password">
 							<la:message key="labels.profile.placeholder_old_password" />
@@ -49,7 +49,7 @@
 						<c:set var="ph_new_password">
 							<la:message key="labels.profile.placeholder_new_password" />
 						</c:set>
-						<la:password property="newPassword" class="form-control"
+						<la:password property="oldPassword" class="form-control"
 									 placeholder="${ph_new_password}" />
 						<div class="input-group-append">
 							<span class="input-group-text"><em class="fa fa-lock fa-fw"></em></span>