From 9a714fb49c842df767cc7ab74e1162b0a4267c7d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Wed, 3 Aug 2016 16:39:23 +0200 Subject: [PATCH] Continued: (please cherry-pick) - rewrote fetching context parameter with protected methods to have this code encapsulated - used this for feature controller - added new user password-change controller (+ interface) to change user's password - used it in template to avoid monolithic super controllers ... - added missing i18n strings - used password-change event for updating user's password history - added new context parameter for "change_user_password" feature - added new context parameter for maximum checked passwords - fixed redirect outcomes MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- nbproject/faces-config.NavData | 127 ++++----- .../jjobs/beans/BaseJobsController.java | 41 +++ .../JobsFeatureWebApplicationBean.java | 66 +++++ .../login/JobsUserLoginWebSessionBean.java | 119 ++++++++- .../JobsUserLoginWebSessionController.java | 18 ++ .../beans/user/JobsUserWebSessionBean.java | 27 +- .../user/JobsUserWebSessionController.java | 9 + .../JobsUserPasswordWebRequestBean.java | 245 ++++++++++++++++++ .../JobsUserPasswordWebRequestController.java | 79 ++++++ .../localization/bundle_de_DE.properties | 3 + .../localization/bundle_en_US.properties | 3 + web/WEB-INF/web.xml | 10 + web/user/login_change_password.xhtml | 96 ++++--- 13 files changed, 742 insertions(+), 101 deletions(-) create mode 100644 src/java/org/mxchange/jjobs/beans/features/JobsFeatureWebApplicationBean.java create mode 100644 src/java/org/mxchange/jjobs/beans/user/password/JobsUserPasswordWebRequestBean.java create mode 100644 src/java/org/mxchange/jjobs/beans/user/password/JobsUserPasswordWebRequestController.java diff --git a/nbproject/faces-config.NavData b/nbproject/faces-config.NavData index 28fad671..00c68c87 100644 --- a/nbproject/faces-config.NavData +++ b/nbproject/faces-config.NavData @@ -2,69 +2,70 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/org/mxchange/jjobs/beans/BaseJobsController.java b/src/java/org/mxchange/jjobs/beans/BaseJobsController.java index 6bb15383..229c64bb 100644 --- a/src/java/org/mxchange/jjobs/beans/BaseJobsController.java +++ b/src/java/org/mxchange/jjobs/beans/BaseJobsController.java @@ -75,4 +75,45 @@ public abstract class BaseJobsController implements Serializable { FacesContext.getCurrentInstance().addMessage(clientId, new FacesMessage(cause.getMessage())); } + /** + * Returns given property key or throws an exception if not found. + *

+ * @param parameterKey Property key + *

+ * @return Property value + *

+ * @throws NullPointerException If given key is not found + * @throws NumberFormatException If no number is given in context parameter + */ + protected int getIntegerContextParameter (final String parameterKey) throws NullPointerException, NumberFormatException { + // Get context parameter + Integer contextValue = Integer.parseInt(this.getStringContextParameter(parameterKey)); + + // Return it + return contextValue; + } + + /** + * Returns given property key or throws an exception if not found. + *

+ * @param parameterKey Property key + *

+ * @return Property value + *

+ * @throws NullPointerException If given key is not found + */ + protected String getStringContextParameter (final String parameterKey) throws NullPointerException { + // Get context parameter + String contextValue = FacesContext.getCurrentInstance().getExternalContext().getInitParameter(parameterKey); + + // Is it null? + if (null == contextValue) { + // Throw NPE + throw new NullPointerException("parameterKey=" + parameterKey + " is not set."); + } + + // Return it + return contextValue; + } + } diff --git a/src/java/org/mxchange/jjobs/beans/features/JobsFeatureWebApplicationBean.java b/src/java/org/mxchange/jjobs/beans/features/JobsFeatureWebApplicationBean.java new file mode 100644 index 00000000..6727e653 --- /dev/null +++ b/src/java/org/mxchange/jjobs/beans/features/JobsFeatureWebApplicationBean.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 Roland Haeder + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.jjobs.beans.features; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Named; +import org.mxchange.jjobs.beans.BaseJobsController; + +/** + * A feature bean + *

+ * @author Roland Haeder + */ +@Named ("featureController") +@ApplicationScoped +public class JobsFeatureWebApplicationBean extends BaseJobsController implements JobsFeaturesWebApplicationController { + + /** + * Serial number + */ + private static final long serialVersionUID = 64_237_512_690_168_674L; + + @Override + public boolean isFeatureEnabled (final String feature) { + // The parameter must be set + if (null == feature) { + // Throw NPE + throw new NullPointerException("feature is null"); //NOI18N + } else if (feature.isEmpty()) { + // Is empty + throw new IllegalArgumentException("feature is empty"); //NOI18N + } + + // Default is not enabled + boolean isEnabled = false; + + // Try it as an NPE may come + try { + // Get value from property + String value = this.getStringContextParameter(String.format("is_feature_%s_enabled", feature)); //NOI18N + + // Is it set? + isEnabled = (value.toLowerCase().equals("true")); //NOI18N + } catch (final NullPointerException ex) { + // Ignored + } + + // Return value + return isEnabled; + } + +} diff --git a/src/java/org/mxchange/jjobs/beans/login/JobsUserLoginWebSessionBean.java b/src/java/org/mxchange/jjobs/beans/login/JobsUserLoginWebSessionBean.java index 41d2d2e5..a0c6aba1 100644 --- a/src/java/org/mxchange/jjobs/beans/login/JobsUserLoginWebSessionBean.java +++ b/src/java/org/mxchange/jjobs/beans/login/JobsUserLoginWebSessionBean.java @@ -16,12 +16,15 @@ */ package org.mxchange.jjobs.beans.login; +import java.text.MessageFormat; import java.util.Collections; import java.util.List; import java.util.Objects; import javax.enterprise.context.SessionScoped; import javax.enterprise.event.Event; +import javax.enterprise.event.Observes; import javax.enterprise.inject.Any; +import javax.faces.context.FacesContext; import javax.faces.view.facelets.FaceletException; import javax.inject.Inject; import javax.inject.Named; @@ -34,6 +37,7 @@ import org.mxchange.jusercore.container.login.LoginContainer; import org.mxchange.jusercore.container.login.UserLoginContainer; import org.mxchange.jusercore.events.login.UserLoggedInEvent; import org.mxchange.jusercore.events.login.UserLoginEvent; +import org.mxchange.jusercore.events.user.password_change.UpdatedUserPasswordEvent; import org.mxchange.jusercore.exceptions.UserNotFoundException; import org.mxchange.jusercore.exceptions.UserPasswordMismatchException; import org.mxchange.jusercore.exceptions.UserStatusLockedException; @@ -136,7 +140,46 @@ public class JobsUserLoginWebSessionBean extends BaseJobsController implements J } @Override - public String doLogin () { + public void afterUserUpdatedPasswordEvent (@Observes final UpdatedUserPasswordEvent event) { + // Check parameter + if (null == event) { + // Throw NPE + throw new NullPointerException("event is null"); //NOI18N + } else if (event.getPasswordHistory() == null) { + // Throw NPE again + throw new NullPointerException("event.passwordHistory is null"); //NOI18N + } else if (event.getPasswordHistory().getUserPasswordHistoryId() == null) { + // ... and again + throw new NullPointerException("event.passwordHistory.userPasswordHistoryId is null"); //NOI18N + } else if (event.getPasswordHistory().getUserPasswordHistoryId() < 1) { + // Invalid value + throw new IllegalArgumentException(MessageFormat.format("event.passwordHistory.userPasswordHistoryId={0} is in valid", event.getPasswordHistory().getUserPasswordHistoryId())); //NOI18N + } + + // All fine, so update list + this.updatePasswordHistory(event.getPasswordHistory()); + } + + @Override + public String doAdminLogout () { + // Is a user logged-in? + if (this.isUserLoggedIn()) { + // Call other logout + return this.doUserLogout(); + } + + // Invalidate session + FacesContext.getCurrentInstance().getExternalContext().invalidateSession(); + + // Set template type to guest + this.setBaseTemplatePathName(GUEST_BASE_TEMPLATE_NAME); //NOI18N + + // Redirect to index + return "index?faces-redirect=true"; //NOI18N + } + + @Override + public String doUserLogin () { // Get user instance User user = this.userController.createUserLogin(); @@ -232,6 +275,35 @@ public class JobsUserLoginWebSessionBean extends BaseJobsController implements J return this.getLoggedInUser().getUserProfileMode().equals(ProfileMode.INVISIBLE); } + @Override + public boolean isPasswordInHistory (final String userPassword) { + // Default is not found + boolean isPasswordInHistory = false; + + // Init variables + int count = 1; + int maxEntries = this.getIntegerContextParameter("max_user_password_history"); //NOI18N + + // Check all passwords + for (final PasswordHistory entry : this.getUserPasswordHistory()) { + // Is password the same? + if (UserUtils.ifPasswordMatches(userPassword, entry.getUserPasswordHistoryUser())) { + // Yes, found it + isPasswordInHistory = true; + break; + } else if (count == maxEntries) { + // Maximum reached + break; + } + + // Count up + count++; + } + + // Return status + return isPasswordInHistory; + } + @Override public boolean isUserLoggedIn () { // Trace message @@ -246,4 +318,49 @@ public class JobsUserLoginWebSessionBean extends BaseJobsController implements J return this.userLoggedIn; } + /** + * Clears this bean + */ + private void clear () { + // Clear all fields + this.setCurrentPassword(null); + } + + /** + * Updates password history by adding given entry to it as long as it is not + * there. + *

+ * @param passwordHistory Password history entry + */ + private void updatePasswordHistory (final PasswordHistory passwordHistory) { + if (null == passwordHistory) { + // Throw NPE + throw new NullPointerException("passwordHistory is null"); //NOI18N + } else if (passwordHistory.getUserPasswordHistoryId() == null) { + // Throw NPE again + throw new NullPointerException("passwordHistory.userPasswordHistoryId is null"); //NOI18N + } else if (passwordHistory.getUserPasswordHistoryId() < 1) { + // Invalid id + throw new IllegalArgumentException(MessageFormat.format("passwordHistory.userPasswordHistoryId={0} is not valid.", passwordHistory.getUserPasswordHistoryId())); //NOI18N + } + + // Is it there? + if (this.userPasswordHistory.contains(passwordHistory)) { + // Excact copy found + return; + } + + // Check all entries + for (final PasswordHistory entry : this.userPasswordHistory) { + // Is same id number? + if (Objects.equals(entry.getUserPasswordHistoryId(), passwordHistory.getUserPasswordHistoryId())) { + // Found it + return; + } + } + + // Not found, so add it + this.userPasswordHistory.add(passwordHistory); + } + } diff --git a/src/java/org/mxchange/jjobs/beans/login/JobsUserLoginWebSessionController.java b/src/java/org/mxchange/jjobs/beans/login/JobsUserLoginWebSessionController.java index fe96c0a0..c99df245 100644 --- a/src/java/org/mxchange/jjobs/beans/login/JobsUserLoginWebSessionController.java +++ b/src/java/org/mxchange/jjobs/beans/login/JobsUserLoginWebSessionController.java @@ -19,6 +19,7 @@ package org.mxchange.jjobs.beans.login; import java.io.Serializable; import java.util.List; import javax.ejb.Local; +import org.mxchange.jusercore.events.user.password_change.UpdatedUserPasswordEvent; import org.mxchange.jusercore.model.user.User; import org.mxchange.jusercore.model.user.password_history.PasswordHistory; @@ -30,6 +31,23 @@ import org.mxchange.jusercore.model.user.password_history.PasswordHistory; @Local public interface JobsUserLoginWebSessionController extends Serializable { + /** + * Method being call after user's password has been updated (and history + * entry has been created). + *

+ * @param event Event being observed + */ + void afterUserUpdatedPasswordEvent (final UpdatedUserPasswordEvent event); + + /** + * Checks whether given clear-text password is in user's password history. + *

+ * @param userPassword Clear-text password + *

+ * @return Whether clear-text password is in user's password history + */ + boolean isPasswordInHistory (final String userPassword); + /** * Getter for template type *

diff --git a/src/java/org/mxchange/jjobs/beans/user/JobsUserWebSessionBean.java b/src/java/org/mxchange/jjobs/beans/user/JobsUserWebSessionBean.java index 65cbfbbf..6cd1f020 100644 --- a/src/java/org/mxchange/jjobs/beans/user/JobsUserWebSessionBean.java +++ b/src/java/org/mxchange/jjobs/beans/user/JobsUserWebSessionBean.java @@ -45,6 +45,7 @@ import org.mxchange.jusercore.events.confirmation.UserConfirmedAccountEvent; import org.mxchange.jusercore.events.login.UserLoggedInEvent; import org.mxchange.jusercore.events.registration.UserRegisteredEvent; import org.mxchange.jusercore.events.user.add.AdminAddedUserEvent; +import org.mxchange.jusercore.events.user.password_change.UpdatedUserPasswordEvent; import org.mxchange.jusercore.events.user.update.AdminUpdatedUserDataEvent; import org.mxchange.jusercore.events.user.update.UpdatedUserPersonalDataEvent; import org.mxchange.jusercore.events.user.update.UserUpdatedPersonalDataEvent; @@ -378,6 +379,27 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs } } + @Override + public void afterUserUpdatedPasswordEvent (@Observes final UpdatedUserPasswordEvent event) { + // Check parameter + if (null == event) { + // Throw NPE + throw new NullPointerException("event is null"); //NOI18N + } else if (event.getPasswordHistory() == null) { + // Throw NPE again + throw new NullPointerException("event.passwordHistory is null"); //NOI18N + } else if (event.getPasswordHistory().getUserPasswordHistoryId() == null) { + // ... and again + throw new NullPointerException("event.passwordHistory.userPasswordHistoryId is null"); //NOI18N + } else if (event.getPasswordHistory().getUserPasswordHistoryId() < 1) { + // Invalid value + throw new IllegalArgumentException(MessageFormat.format("event.passwordHistory.userPasswordHistoryId={0} is in valid", event.getPasswordHistory().getUserPasswordHistoryId())); //NOI18N + } + + // All fine, so update list + this.updateList(event.getPasswordHistory().getUserPasswordHistoryUser()); + } + @Override public void afterUserUpdatedPersonalData (@Observes final UpdatedUserPersonalDataEvent event) { // Check parameter @@ -502,6 +524,9 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs } else if (!this.userLoginController.ifCurrentPasswordMatches()) { // Password not matching throw new FaceletException(new UserPasswordMismatchException(this.userLoginController.getLoggedInUser())); + } else if (!this.featureController.isFeatureEnabled("edit_user_data")) { + // Editing is not allowed + throw new IllegalStateException("User tried to edit personal data."); //NOI18N } // Get user instance @@ -528,7 +553,7 @@ public class JobsUserWebSessionBean extends BaseJobsController implements JobsUs this.updatedPersonalDataEvent.fire(new UserUpdatedPersonalDataEvent(updatedUser)); // All fine - return "user_data_saved"; //NOI18N + return "contact_data_saved"; //NOI18N } @Override diff --git a/src/java/org/mxchange/jjobs/beans/user/JobsUserWebSessionController.java b/src/java/org/mxchange/jjobs/beans/user/JobsUserWebSessionController.java index ba624983..c004b24d 100644 --- a/src/java/org/mxchange/jjobs/beans/user/JobsUserWebSessionController.java +++ b/src/java/org/mxchange/jjobs/beans/user/JobsUserWebSessionController.java @@ -24,6 +24,7 @@ import org.mxchange.jusercore.events.confirmation.UserConfirmedAccountEvent; import org.mxchange.jusercore.events.login.UserLoggedInEvent; import org.mxchange.jusercore.events.registration.UserRegisteredEvent; import org.mxchange.jusercore.events.user.add.AdminAddedUserEvent; +import org.mxchange.jusercore.events.user.password_change.UpdatedUserPasswordEvent; import org.mxchange.jusercore.events.user.update.AdminUpdatedUserDataEvent; import org.mxchange.jusercore.events.user.update.UpdatedUserPersonalDataEvent; import org.mxchange.jusercore.exceptions.UserEmailAddressNotFoundException; @@ -72,6 +73,14 @@ public interface JobsUserWebSessionController extends Serializable { */ void afterUserConfirmedAccount (final UserConfirmedAccountEvent event); + /** + * Method being call after user's password has been updated (and history + * entry has been created). + *

+ * @param event Event being observed + */ + void afterUserUpdatedPasswordEvent (final UpdatedUserPasswordEvent event); + /** * Listens to fired event when user updated personal data *

diff --git a/src/java/org/mxchange/jjobs/beans/user/password/JobsUserPasswordWebRequestBean.java b/src/java/org/mxchange/jjobs/beans/user/password/JobsUserPasswordWebRequestBean.java new file mode 100644 index 00000000..eae35158 --- /dev/null +++ b/src/java/org/mxchange/jjobs/beans/user/password/JobsUserPasswordWebRequestBean.java @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2016 Cho-Time GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.jjobs.beans.user.password; + +import java.util.Objects; +import javax.enterprise.context.RequestScoped; +import javax.enterprise.event.Event; +import javax.enterprise.inject.Any; +import javax.faces.view.facelets.FaceletException; +import javax.inject.Inject; +import javax.inject.Named; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import org.mxchange.addressbook.beans.BaseAddressbookController; +import org.mxchange.addressbook.beans.features.AddressbookFeaturesWebApplicationController; +import org.mxchange.addressbook.beans.login.AddressbookUserLoginWebSessionController; +import org.mxchange.jusercore.events.user.password_change.UpdatedUserPasswordEvent; +import org.mxchange.jusercore.events.user.password_change.UserUpdatedPasswordEvent; +import org.mxchange.jusercore.exceptions.UserNotFoundException; +import org.mxchange.jusercore.exceptions.UserPasswordMismatchException; +import org.mxchange.jusercore.exceptions.UserStatusLockedException; +import org.mxchange.jusercore.exceptions.UserStatusUnconfirmedException; +import org.mxchange.jusercore.model.user.User; +import org.mxchange.jusercore.model.user.UserSessionBeanRemote; +import org.mxchange.jusercore.model.user.UserUtils; +import org.mxchange.jusercore.model.user.password_history.PasswordHistory; + +/** + * A user password (change) bean (controller) + *

+ * @author Roland Haeder + */ +@Named ("userPasswordController") +@RequestScoped +public class JobsUserPasswordWebRequestBean extends BaseAddressbookController implements JobsUserPasswordWebRequestController { + + /** + * Serial number + */ + private static final long serialVersionUID = 15_267_867_367_501L; + + /** + * Features controller + */ + @Inject + private AddressbookFeaturesWebApplicationController featureController; + + /** + * Remote user bean + */ + private final UserSessionBeanRemote userBean; + + /** + * Current password (for confirmation of password change) + */ + private String userCurrentPassword; + + /** + * Login bean (controller) + */ + @Inject + private AddressbookUserLoginWebSessionController userLoginController; + + /** + * User password (unencrypted from web form) + */ + private String userPassword; + + /** + * User password repeated (unencrypted from web form) + */ + private String userPasswordRepeat; + + /** + * Event being fired when user's password has been updated + */ + @Any + @Inject + private Event userUpdatedPasswordEvent; + + /** + * Default constructor + */ + public JobsUserPasswordWebRequestBean () { + // Try it + try { + // Get initial context + Context context = new InitialContext(); + + // Try to lookup + this.userBean = (UserSessionBeanRemote) context.lookup("java:global/jlandingpage-ejb/user!org.mxchange.jusercore.model.user.UserSessionBeanRemote"); //NOI18N + } catch (final NamingException e) { + // Throw again + throw new FaceletException(e); + } + } + + @Override + public String doChangePassword () { + // This method shall only be called if the user is logged-in + if (!this.userLoginController.isUserLoggedIn()) { + // Not logged-in + throw new IllegalStateException("User is not logged-in"); //NOI18N + } else if (!this.isRequiredChangePasswordSet()) { + // Not all required fields are set + throw new FaceletException("Not all required fields are set."); //NOI18N + } else if (!this.userLoginController.ifCurrentPasswordMatches()) { + // Password not matching + throw new FaceletException(new UserPasswordMismatchException(this.userLoginController.getLoggedInUser())); + } else if (!this.featureController.isFeatureEnabled("change_user_password")) { //NOI18N + // Editing is not allowed + throw new IllegalStateException("User tried to change password."); //NOI18N + } else if (!UserUtils.ifPasswordMatches(this.getUserCurrentPassword(), this.userLoginController.getLoggedInUser())) { + // Password mismatches + this.showFacesMessage("form_user_change_password:userCurrentPassword", "Entered current password does not matched stored password."); //NOI18N + + // Clear bean + this.clear(); + + // No redirect + return ""; //NOI18N + } else if (!Objects.equals(this.getUserPassword(), this.getUserPasswordRepeat())) { + // Both entered passwords don't match + this.showFacesMessage("form_user_change_password:userPasswordRepeat", "Entered new passwords mismatch."); //NOI18N + + // Clear bean + this.clear(); + + // No redirect + return ""; //NOI18N + } else if (Objects.equals(this.getUserCurrentPassword(), this.getUserPassword())) { + // New password matches current + this.showFacesMessage("form_user_change_password:userPassword", "Entered new password is same as current password."); //NOI18N + + // Clear bean + this.clear(); + + // No redirect + return ""; //NOI18N + } else if (this.userLoginController.isPasswordInHistory(this.getUserPassword())) { + // Is already in list (to old passwords are ignored) + this.showFacesMessage("form_user_change_password:userPassword", "Entered new password is has already been used some time ago."); //NOI18N + + // Clear bean + this.clear(); + + // No redirect + return ""; //NOI18N + } + + // Get user instance + User user = this.userLoginController.getLoggedInUser(); + + // Encrypt password + String encryptedPassword = UserUtils.encryptPassword(this.getUserPassword()); + + // Set it in user + user.setUserEncryptedPassword(encryptedPassword); + + try { + // All is set, then update password + PasswordHistory passwordHistory = this.userBean.updateUserPassword(user); + + // Fire event + this.userUpdatedPasswordEvent.fire(new UserUpdatedPasswordEvent(passwordHistory)); + } catch (final UserNotFoundException | UserStatusUnconfirmedException | UserStatusLockedException ex) { + // Clear bean + this.clear(); + + // Throw again + throw new FaceletException(ex); + } + + // Clear bean + this.clear(); + + // Return outcome + return "login_data_saved"; //NOI18N + } + + @Override + public String getUserCurrentPassword () { + return this.userCurrentPassword; + } + + @Override + public void setUserCurrentPassword (final String userCurrentPassword) { + this.userCurrentPassword = userCurrentPassword; + } + + @Override + public String getUserPassword () { + return this.userPassword; + } + + @Override + public void setUserPassword (final String userPassword) { + this.userPassword = userPassword; + } + + @Override + public String getUserPasswordRepeat () { + return this.userPasswordRepeat; + } + + @Override + public void setUserPasswordRepeat (final String userPasswordRepeat) { + this.userPasswordRepeat = userPasswordRepeat; + } + + public boolean isRequiredChangePasswordSet () { + // Is all data set? + return ((this.getUserCurrentPassword() != null) && + (!this.getUserCurrentPassword().isEmpty()) && + (this.getUserPassword() != null) && + (!this.getUserPassword().isEmpty()) && + (this.getUserPasswordRepeat() != null) && + (!this.getUserPasswordRepeat().isEmpty())); + } + + /** + * Clears this bean + */ + private void clear () { + // Clear all data + this.setUserPassword(null); + this.setUserPasswordRepeat(null); + } + +} diff --git a/src/java/org/mxchange/jjobs/beans/user/password/JobsUserPasswordWebRequestController.java b/src/java/org/mxchange/jjobs/beans/user/password/JobsUserPasswordWebRequestController.java new file mode 100644 index 00000000..73767ba4 --- /dev/null +++ b/src/java/org/mxchange/jjobs/beans/user/password/JobsUserPasswordWebRequestController.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 Cho-Time GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.jjobs.beans.user.password; + +import java.io.Serializable; +import javax.ejb.Local; + +/** + * An interface for user beans + *

+ * @author Roland Haeder + */ +@Local +public interface JobsUserPasswordWebRequestController extends Serializable { + + /** + * Getter for unencrypted user password + *

+ * @return Unencrypted user password + */ + String getUserPassword (); + + /** + * Setter for unencrypted user password + *

+ * @param userPassword Unencrypted user password + */ + void setUserPassword (final String userPassword); + + /** + * Getter for current unencrypted user password + *

+ * @return Current unencrypted user password + */ + String getUserCurrentPassword (); + + /** + * Setter for current unencrypted user password + *

+ * @param userCurrentPassword Current unencrypted user password + */ + void setUserCurrentPassword (final String userCurrentPassword); + + /** + * Getter for unencrypted user password repeated + *

+ * @return Unencrypted user password repeated + */ + String getUserPasswordRepeat (); + + /** + * Setter for unencrypted user password repeated + *

+ * @param userPasswordRepeat Unencrypted user password repeated + */ + void setUserPasswordRepeat (final String userPasswordRepeat); + + /** + * Changes logged-in user's password. It must not match with current password and should not appear in password history list for X (configurable) entries. + *

+ * @return Redirect outcome + */ + String doChangePassword (); + +} diff --git a/src/java/org/mxchange/localization/bundle_de_DE.properties b/src/java/org/mxchange/localization/bundle_de_DE.properties index dd7188b4..971babf7 100644 --- a/src/java/org/mxchange/localization/bundle_de_DE.properties +++ b/src/java/org/mxchange/localization/bundle_de_DE.properties @@ -584,3 +584,6 @@ ADMIN_MOBILE_PROVIDER_DIAL_PREFIX_REQUIRED=Bitte geben Sie die Vorwahl ohne f\u0 USER_LOGIN_MUST_CHANGE_PASSWORD=Sie m\u00fcssen Ihr Passwort \u00e4ndern. Dies darf nicht mit dem aktuellen \u00fcbereinstimmen. ADMIN_LOGOUT_TITLE=Aus dem Administrationsbereich ausloggen ADMIN_LOGOUT_NOTICE=Bitte loggen Sie sich immer aus, damit die Sitzung sauber beendet ist. Andere M\u00f6gliichkeit ist, den Browser zu schhlie\u00dfen, dann wird die Sitzung auch beendet. +USER_CURRENT_PASSWORD_REQUIRED=Bitte geben Sie Ihr derzeit verwendetes Passwort zur \u00c4nderungsbest\u00e4tigung ein. +USER_NEW_PASSWORD_REQUIRED=Bitte geben Sie ein neues Passwort zweimal ein. Dieses muss anders als Ihr aktuelles sein. +USER_NEW_PASSWORD_REPEAT_REQUIRED=Bitte wiederholen Sie das neue Passwort. Dies dient der Reduzierung von Tippfehlern. diff --git a/src/java/org/mxchange/localization/bundle_en_US.properties b/src/java/org/mxchange/localization/bundle_en_US.properties index cbf32310..5f321246 100644 --- a/src/java/org/mxchange/localization/bundle_en_US.properties +++ b/src/java/org/mxchange/localization/bundle_en_US.properties @@ -584,3 +584,6 @@ ADMIN_MOBILE_PROVIDER_DIAL_PREFIX_REQUIRED=Please enter dial prefix for mobile p USER_LOGIN_MUST_CHANGE_PASSWORD=Please change your password. It must not match with your current one. ADMIN_LOGOUT_TITLE=Logout from administration area ADMIN_LOGOUT_NOTICE=Please always logout from administration area that the session is cleanly closed. An other option is to close the browser, then the session is also closed. +USER_CURRENT_PASSWORD_REQUIRED=Please enter your currently used password for confirming password change. +USER_NEW_PASSWORD_REQUIRED=Please a new password twice. This must be different than the current one. +USER_NEW_PASSWORD_REPEAT_REQUIRED=Please repeat your new password. This is for preventing type mistakes. diff --git a/web/WEB-INF/web.xml b/web/WEB-INF/web.xml index 40fa93ae..da0d52cf 100644 --- a/web/WEB-INF/web.xml +++ b/web/WEB-INF/web.xml @@ -71,6 +71,16 @@ is_feature_user_must_change_password_enabled true + + Whether users are allowed to change their login password. + is_feature_change_user_password_enabled + true + + + Maximum passwords that must be different. + max_user_password_history + 5 + Faces Servlet javax.faces.webapp.FacesServlet diff --git a/web/user/login_change_password.xhtml b/web/user/login_change_password.xhtml index ae17f9f9..eb3f15dd 100644 --- a/web/user/login_change_password.xhtml +++ b/web/user/login_change_password.xhtml @@ -16,56 +16,80 @@ -

-
- -
+ +
+
+ +
+ + +
+
+ + + + +
+
+ +
- -
-
- - - +
+ +
-
-
- +
-
- +
+
-
-
+
+
+ +
-
-
- +
+ +
-
- +
+
-
-
-
-
+
+
+ +
- +
+ +
+
- -
-
- +
+ +
+
+
+ + +
+
+ + + + +
- - + + + -- 2.39.5