fix #2497 update admin password
This commit is contained in:
parent
ed46ec4b51
commit
ba8848097e
14 changed files with 252 additions and 5 deletions
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -25,8 +25,11 @@ public class LoginForm {
|
|||
@NotBlank
|
||||
public String password;
|
||||
|
||||
public String confirmPassword;
|
||||
|
||||
public void clearSecurityInfo() {
|
||||
password = null;
|
||||
confirmPassword = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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=更新
|
|
@ -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
src/main/webapp/WEB-INF/view/login/newpassword.jsp
Normal file
81
src/main/webapp/WEB-INF/view/login/newpassword.jsp
Normal file
|
@ -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>
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Reference in a new issue