From 88cdbe8fcf8da087e35a2eca971551013e7b7ce1 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Roland=20H=C3=A4der?= <roland@mxchange.org>
Date: Thu, 22 Jun 2017 22:52:09 +0200
Subject: [PATCH] Please cherry-pick: - New feature to allow users on
 registration entering no password. The   application will then generate a
 random password for the user and also sends   it in clear-text to the EJB
 (HTTPS is not meant here) so the bean can deliver   it to the user. - user
 registration page will now show proper messages for above feature - removed
 obsolete template (seems to be still around?) - ifBothPasswordsEmptyAllowed()
 implemented - added missing i18n strings
MIME-Version: 1.0
Content-Type: text/plain; charset=utf8
Content-Transfer-Encoding: 8bit

Signed-off-by: Roland Häder <roland@mxchange.org>
---
 ...AddressbookAdminContactWebRequestBean.java |   2 +-
 .../AddressbookContactWebSessionBean.java     |   2 +-
 .../user/AddressbookUserWebSessionBean.java   |   8 ++
 .../AddressbookUserWebSessionController.java  |  10 ++
 ...AddressbookUserRegisterWebSessionBean.java | 100 +++++++++++++---
 .../localization/bundle_de_DE.properties      |  30 +++++
 .../localization/bundle_en_US.properties      |  18 +++
 .../guest/user/guest_registration_form.tpl    | 108 ------------------
 .../register/guest_form_register_page1.tpl    |  10 +-
 .../register/guest_form_register_single.tpl   |  10 +-
 web/WEB-INF/web.xml                           |   5 +
 web/guest/user/user_register.xhtml            |   4 +-
 12 files changed, 176 insertions(+), 131 deletions(-)
 delete mode 100644 web/WEB-INF/templates/guest/user/guest_registration_form.tpl

diff --git a/src/java/org/mxchange/addressbook/beans/contact/AddressbookAdminContactWebRequestBean.java b/src/java/org/mxchange/addressbook/beans/contact/AddressbookAdminContactWebRequestBean.java
index 80fff898..3d95cba4 100644
--- a/src/java/org/mxchange/addressbook/beans/contact/AddressbookAdminContactWebRequestBean.java
+++ b/src/java/org/mxchange/addressbook/beans/contact/AddressbookAdminContactWebRequestBean.java
@@ -37,7 +37,7 @@ import org.mxchange.jcontacts.contact.Contact;
 import org.mxchange.jcontacts.contact.ContactSessionBeanRemote;
 import org.mxchange.jcontacts.contact.UserContact;
 import org.mxchange.jcontacts.contact.title.PersonalTitle;
-import org.mxchange.jcontacts.contact.utils.ContactUtils;
+import org.mxchange.jcontacts.contact.ContactUtils;
 import org.mxchange.jcontacts.events.contact.add.AdminAddedContactEvent;
 import org.mxchange.jcontacts.events.contact.add.ObservableAdminAddedContactEvent;
 import org.mxchange.jcontacts.events.contact.update.AdminUpdatedContactEvent;
diff --git a/src/java/org/mxchange/addressbook/beans/contact/AddressbookContactWebSessionBean.java b/src/java/org/mxchange/addressbook/beans/contact/AddressbookContactWebSessionBean.java
index 627db6cb..b23b6d17 100644
--- a/src/java/org/mxchange/addressbook/beans/contact/AddressbookContactWebSessionBean.java
+++ b/src/java/org/mxchange/addressbook/beans/contact/AddressbookContactWebSessionBean.java
@@ -39,7 +39,7 @@ import org.mxchange.jcontacts.contact.Contact;
 import org.mxchange.jcontacts.contact.ContactSessionBeanRemote;
 import org.mxchange.jcontacts.contact.UserContact;
 import org.mxchange.jcontacts.contact.title.PersonalTitle;
-import org.mxchange.jcontacts.contact.utils.ContactUtils;
+import org.mxchange.jcontacts.contact.ContactUtils;
 import org.mxchange.jcontacts.events.contact.add.ObservableAdminAddedContactEvent;
 import org.mxchange.jcontacts.events.contact.update.ObservableAdminUpdatedContactEvent;
 import org.mxchange.jcontacts.exceptions.ContactNotFoundException;
diff --git a/src/java/org/mxchange/addressbook/beans/user/AddressbookUserWebSessionBean.java b/src/java/org/mxchange/addressbook/beans/user/AddressbookUserWebSessionBean.java
index 0ce52698..c77ed045 100644
--- a/src/java/org/mxchange/addressbook/beans/user/AddressbookUserWebSessionBean.java
+++ b/src/java/org/mxchange/addressbook/beans/user/AddressbookUserWebSessionBean.java
@@ -660,6 +660,14 @@ public class AddressbookUserWebSessionBean extends BaseAddressbookController imp
 		this.userProfileMode = userProfileMode;
 	}
 
+	@Override
+	public boolean ifBothPasswordsEmptyAllowed () {
+		// Check feature first
+		return ((this.featureController.isFeatureEnabled("allow_user_registration_empty_password")) &&
+				((this.getUserPassword() == null) || (this.getUserPassword().isEmpty())) &&
+				((this.getUserPasswordRepeat() == null) || (this.getUserPasswordRepeat().isEmpty())));
+	}
+
 	/**
 	 * Post-initialization of this class
 	 */
diff --git a/src/java/org/mxchange/addressbook/beans/user/AddressbookUserWebSessionController.java b/src/java/org/mxchange/addressbook/beans/user/AddressbookUserWebSessionController.java
index c2148e67..eb030be3 100644
--- a/src/java/org/mxchange/addressbook/beans/user/AddressbookUserWebSessionController.java
+++ b/src/java/org/mxchange/addressbook/beans/user/AddressbookUserWebSessionController.java
@@ -36,6 +36,16 @@ public interface AddressbookUserWebSessionController extends Serializable {
 	 */
 	public static final Integer MINIMUM_PASSWORD_LENGTH = 5;
 
+	/**
+	 * Checks if both user passwords are left empty and if this is enabled
+	 * (allowed) in context parameter. If true, the calling bean should create a
+	 * random password (preferable with UserUtils.createRandomPassword() and set
+	 * it in both user password fields.
+	 * <p>
+	 * @return Whether empty passwords are allowed
+	 */
+	boolean ifBothPasswordsEmptyAllowed ();
+
 	/**
 	 * All users
 	 * <p>
diff --git a/src/java/org/mxchange/addressbook/beans/user/register/AddressbookUserRegisterWebSessionBean.java b/src/java/org/mxchange/addressbook/beans/user/register/AddressbookUserRegisterWebSessionBean.java
index 07ff07aa..43bdf21e 100644
--- a/src/java/org/mxchange/addressbook/beans/user/register/AddressbookUserRegisterWebSessionBean.java
+++ b/src/java/org/mxchange/addressbook/beans/user/register/AddressbookUserRegisterWebSessionBean.java
@@ -40,9 +40,9 @@ import org.mxchange.jusercore.events.registration.UserRegisteredEvent;
 import org.mxchange.jusercore.exceptions.DataRepeatMismatchException;
 import org.mxchange.jusercore.exceptions.EmailAddressAlreadyRegisteredException;
 import org.mxchange.jusercore.exceptions.UserNameAlreadyRegisteredException;
-import org.mxchange.jusercore.model.register.UserRegistrationSessionBeanRemote;
 import org.mxchange.jusercore.model.user.User;
 import org.mxchange.jusercore.model.user.UserUtils;
+import org.mxchange.jusercore.model.user.register.UserRegistrationSessionBeanRemote;
 import org.mxchange.jusercore.model.user.status.UserAccountStatus;
 
 /**
@@ -114,6 +114,9 @@ public class AddressbookUserRegisterWebSessionBean extends BaseAddressbookContro
 		// Get user instance
 		User user = this.userController.createUserInstance(true);
 
+		// Null random password means registration requires user-entered password
+		String randomPassword = null;
+
 		// Is the user already used?
 		if (null == user) {
 			// user must be set
@@ -122,17 +125,53 @@ public class AddressbookUserRegisterWebSessionBean extends BaseAddressbookContro
 			// Not all required fields are set
 			throw new FaceletException("Not all required fields are set."); //NOI18N
 		} else if ((this.featureController.isFeatureEnabled("user_name_required")) && (this.userController.isUserNameRegistered(user))) { //NOI18N
-			// User name is already used
-			throw new FaceletException(new UserNameAlreadyRegisteredException(user));
+			// Is multi-page enabled?
+			if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
+				// User name is already used, should not happen here
+				throw new FaceletException(new UserNameAlreadyRegisteredException(user));
+			} else {
+				// May happen here, reset field
+				this.userController.setUserName(null);
+				this.showFacesMessage("form_register_single:userName", "ERROR_USER_NAME_ALREADY_USED"); //NOI18N
+				return ""; //NOI18N
+			}
 		} else if (this.contactController.isEmailAddressRegistered(user.getUserContact())) {
-			// Email address has already been taken
-			throw new FaceletException(new EmailAddressAlreadyRegisteredException(user));
+			// Is multi-page enabled?
+			if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
+				// Email address has already been taken, should not happen here
+				throw new FaceletException(new EmailAddressAlreadyRegisteredException(user));
+			} else {
+				// May happen here, reset fields
+				this.contactController.setEmailAddress(null);
+				this.contactController.setEmailAddressRepeat(null);
+				this.showFacesMessage("form_register_single:emailAddressRepeat", "ERROR_EMAIL_ADDRESS_ALREADY_USED"); //NOI18N
+				return ""; //NOI18N
+			}
 		} else if (!this.contactController.isSameEmailAddressEntered()) {
-			// Not same email address entered
-			throw new FaceletException(new DataRepeatMismatchException(MessageFormat.format("Email addresses not matching: {0} != {1}", this.contactController.getEmailAddress(), this.contactController.getEmailAddressRepeat()))); //NOI18N
+			// Is multi-page enabled?
+			if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
+				// Not same email address entered, should not happen here
+				throw new FaceletException(new DataRepeatMismatchException(MessageFormat.format("Email addresses not matching: {0} != {1}", this.contactController.getEmailAddress(), this.contactController.getEmailAddressRepeat()))); //NOI18N
+			} else {
+				// May happen here, reset fields
+				this.contactController.setEmailAddress(null);
+				this.contactController.setEmailAddressRepeat(null);
+				this.showFacesMessage("form_register_single:emailAddressRepeat", "ERROR_EMAIL_ADDRESSES_MISMATCHING"); //NOI18N
+				return ""; //NOI18N
+			}
 		} else if (!this.userController.isSamePasswordEntered()) {
-			// Not same password entered
-			throw new FaceletException(new DataRepeatMismatchException("Passwords not matching.")); //NOI18N
+			// Is multi-page enabled?
+			if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
+				// Not same password entered, should no longer happen here
+				throw new FaceletException(new DataRepeatMismatchException("Passwords not matching.")); //NOI18N
+			} else if (this.userController.ifBothPasswordsEmptyAllowed()) {
+				// Both passwords are left empty and is allowed, then generate a random password
+				randomPassword = UserUtils.createRandomPassword(AddressbookUserWebSessionController.MINIMUM_PASSWORD_LENGTH);
+
+				// Set it in both fields
+				this.userController.setUserPassword(randomPassword);
+				this.userController.setUserPasswordRepeat(randomPassword);
+			}
 		}
 
 		// Encrypt password
@@ -161,7 +200,7 @@ public class AddressbookUserRegisterWebSessionBean extends BaseAddressbookContro
 			String baseUrl = FacesUtils.generateBaseUrl();
 
 			// Call bean
-			User registeredUser = this.registerBean.registerUser(user, baseUrl);
+			User registeredUser = this.registerBean.registerUser(user, baseUrl, randomPassword);
 
 			// The id number should be set
 			assert (registeredUser.getUserId() instanceof Long) : "registeredUser.userId is null after registerUser() was called."; //NOI18N
@@ -193,11 +232,35 @@ public class AddressbookUserRegisterWebSessionBean extends BaseAddressbookContro
 			// user must be set
 			throw new NullPointerException("user is null after createUserInstance() was called"); //NOI18N
 		} else if ((this.featureController.isFeatureEnabled("user_name_required")) && (this.userController.isUserNameRegistered(user))) { //NOI18N
-			// User name is already used
-			throw new FaceletException(new UserNameAlreadyRegisteredException(user));
+			// User name is already used, so clear it
+			this.userController.setUserName(null);
+			this.showFacesMessage("form_register_page1:userName", "ERROR_USER_NAME_ALREADY_USED"); //NOI18N
+			return ""; //NOI18N
 		} else if (!this.contactController.isSameEmailAddressEntered()) {
-			// Not same email address entered
-			throw new FaceletException(new DataRepeatMismatchException(MessageFormat.format("Email addresses not matching: {0} != {1}", this.contactController.getEmailAddress(), this.contactController.getEmailAddressRepeat()))); //NOI18N
+			// Not same email address entered, clear both
+			this.contactController.setEmailAddress(null);
+			this.contactController.setEmailAddressRepeat(null);
+			this.showFacesMessage("form_register_page1:emailAddressRepeat", "ERROR_EMAIL_ADDRESSES_MISMATCHING"); //NOI18N
+			return ""; //NOI18N
+		} else if (!this.userController.isSamePasswordEntered()) {
+			// Is multi-page enabled?
+			if (this.featureController.isFeatureEnabled("user_register_multiple_page")) { //NOI18N
+				// Unset both
+				this.userController.setUserPassword(null);
+				this.userController.setUserPasswordRepeat(null);
+
+				// Output faces message
+				this.showFacesMessage("form_register_page1:userPassword", "ERROR_USER_PASSWORD_EMPTY"); //NOI18N
+				this.showFacesMessage("form_register_page1:userPasswordRepeat", "ERROR_USER_PASSWORD_REPEAT_EMPTY"); //NOI18N
+				return ""; //NOI18N
+			} else if (this.userController.ifBothPasswordsEmptyAllowed()) {
+				// Both passwords are left empty and is allowed, then generate a random password
+				String randomPassword = UserUtils.createRandomPassword(AddressbookUserWebSessionController.MINIMUM_PASSWORD_LENGTH);
+
+				// Set it in both fields
+				this.userController.setUserPassword(randomPassword);
+				this.userController.setUserPasswordRepeat(randomPassword);
+			}
 		}
 
 		// Create half contact instance with email address
@@ -209,12 +272,15 @@ public class AddressbookUserRegisterWebSessionBean extends BaseAddressbookContro
 
 		// Check if email address is registered
 		if (this.contactController.isEmailAddressRegistered(user.getUserContact())) {
-			// Email address has already been taken
-			throw new FaceletException(new EmailAddressAlreadyRegisteredException(user));
+			// Email address has already been taken, clear both
+			this.contactController.setEmailAddress(null);
+			this.contactController.setEmailAddressRepeat(null);
+			this.showFacesMessage("form_register_page1:emailAddress", "ERROR_EMAIL_ADDRESS_ALREADY_USED"); //NOI18N
+			return ""; //NOI18N
 		}
 
 		// Now only redirect to next page as the JSF does it
-		return "user_register_page2"; //NOI18N
+		return "register_page2"; //NOI18N
 	}
 
 	/**
diff --git a/src/java/org/mxchange/localization/bundle_de_DE.properties b/src/java/org/mxchange/localization/bundle_de_DE.properties
index c1707360..a0e64af5 100644
--- a/src/java/org/mxchange/localization/bundle_de_DE.properties
+++ b/src/java/org/mxchange/localization/bundle_de_DE.properties
@@ -831,3 +831,33 @@ ADMIN_LINK_SHOW_CONTACT_DATA=Kontaktdaten anzeigen
 ERROR_USER_PASSWORD_TO_WEAK=Das eingegebene Passwort ist zu schwach. Bitte geben Sie Bustaben, Zahlen und Sonderzeichen ein, um ein sicheres Passwort zu erstellen.
 #@TODO Please fix German umlauts!
 GUEST_REGISTRATION_USER_NAME_NOT_ENTERED=Bitte geben Sie einen Benutzernamen ein. Dieser wird auf Verfuegbarkeit hin getestet.
+#@TODO Please fix German umlauts!
+PAGE_TITLE_LOGIN_FINANCIAL_OVERVIEW=Finanzen-Uebersicht
+#@TODO Please fix German umlauts!
+SUB_TITLE_LOGIN_FINANCIAL_OVERVIEW=Uebersicht Ihrer Finanzen:
+#@TODO Please fix German umlauts!
+PAGE_TITLE_LOGIN_FINANCIAL_ADD_RECEIPT=Rechnung hinzufuegen/erfassen
+SUB_TITLE_LOGIN_FINANCIAL_ADD_RECEIPT=Weitere Rechnung erfassen:
+#@TODO Please fix German umlauts!
+PAGE_TITLE_LOGIN_FINANCIAL_ADD_INCOME=Neue Einkommensart hinzufuegen
+#@TODO Please fix German umlauts!
+SUB_TITLE_LOGIN_FINANCIAL_ADD_INCOME=Weitere Einkommensart hinzufuegen:
+LOGIN_FINANCIAL_ADD_INCOME_FORM_TITLE=Daten einer Einkommensart erfassen:
+LOGIN_FINANCIAL_INCOME_INTERVAL=Einkommensinterval:
+#@TODO Please fix German umlauts!
+FIELD_FINANCIAL_INCOME_REQUIRED=Feld "Einkommensinterval" muss ausgewaehlt werden.
+#@TODO Please fix German umlauts!
+BUTTON_LOGIN_FINCIAL_ADD_INCOME=Einkommensart hinzufuegen
+LOGIN_FINANCIAL_INCOME_SINGLE_VALUE=Einkommensbetrag:
+#@TODO Please fix German umlauts!
+FIELD_FINANCIAL_INCOME_SINGLE_VALUE_REQUIRED=Feld "Einkommensbetrag" bitte ausfuellen.
+LOGIN_FINANCIAL_INCOME_TITLE=Bezeichnung der Einkommensart:
+#@TODO Please fix German umlauts!
+FIELD_FINANCIAL_INCOME_TITLE_REQUIRED=Feld "Title" muss ausgefuellt werden.
+#@TODO Please fix German umlauts!
+ERROR_USER_PASSWORD_EMPTY=Sie muessen ein Passwort eingeben.
+#@TODO Please fix German umlauts!
+ERROR_USER_PASSWORD_REPEAT_EMPTY=Sie muessen das eingegebene Passwort wiederholen.
+GUEST_REGISTRATION_USER_PASSWORDS_EMPTY_ALLOWED=Lassen Sie beide Passwortfelder leer, wird Ihnen ein Passwort per Zufall generiert.
+#@TODO Please fix German umlauts!
+GUEST_REGISTRATION_USER_PASSWORDS_EMPTY_NOT_ALLOWED=Sie muessen selbst ein Passwort vergeben. Bitte geben Sie dies zur Bestaetigung zweimal ein.
diff --git a/src/java/org/mxchange/localization/bundle_en_US.properties b/src/java/org/mxchange/localization/bundle_en_US.properties
index dbf5604f..d42c7e11 100644
--- a/src/java/org/mxchange/localization/bundle_en_US.properties
+++ b/src/java/org/mxchange/localization/bundle_en_US.properties
@@ -827,3 +827,21 @@ BUTTON_USER_CHANGE_PASSWORD=Change password
 ADMIN_LINK_SHOW_CONTACT_DATA=Show contact data
 ERROR_USER_PASSWORD_TO_WEAK=Your entered password is to weak. Please enter letters, numbers and special characters to create a secure password.
 GUEST_REGISTRATION_USER_NAME_NOT_ENTERED=Please enter a user name. The entered name is being checked for availability.
+PAGE_TITLE_LOGIN_FINANCIAL_OVERVIEW=Financials Overview
+SUB_TITLE_LOGIN_FINANCIAL_OVERVIEW=Overview of your financials:
+PAGE_TITLE_LOGIN_FINANCIAL_ADD_RECEIPT=Add receipt
+SUB_TITLE_LOGIN_FINANCIAL_ADD_RECEIPT=Add new receipt:
+PAGE_TITLE_LOGIN_FINANCIAL_ADD_INCOME=Add new income type
+SUB_TITLE_LOGIN_FINANCIAL_ADD_INCOME=Add new income type:
+LOGIN_FINANCIAL_ADD_INCOME_FORM_TITLE=Enter all data of one income type:
+LOGIN_FINANCIAL_INCOME_INTERVAL=Income interval:
+FIELD_FINANCIAL_INCOME_REQUIRED=Field "Income interval" must be selected.
+BUTTON_LOGIN_FINCIAL_ADD_INCOME=Add income type
+LOGIN_FINANCIAL_INCOME_SINGLE_VALUE=Income value:
+FIELD_FINANCIAL_INCOME_SINGLE_VALUE_REQUIRED=Field "Income value" must be filled out.
+LOGIN_FINANCIAL_INCOME_TITLE=Title of income type:
+FIELD_FINANCIAL_INCOME_TITLE_REQUIRED=Field "Title" must be filled out.
+ERROR_USER_PASSWORD_EMPTY=You have to enter a password.
+ERROR_USER_PASSWORD_REPEAT_EMPTY=You have to repeat the entered password.
+GUEST_REGISTRATION_USER_PASSWORDS_EMPTY_ALLOWED=If you left both password fields empty, a random password will generated for you.
+GUEST_REGISTRATION_USER_PASSWORDS_EMPTY_NOT_ALLOWED=You have to enter an own password. Please enter it twice for confirmation.
diff --git a/web/WEB-INF/templates/guest/user/guest_registration_form.tpl b/web/WEB-INF/templates/guest/user/guest_registration_form.tpl
deleted file mode 100644
index 7c46749d..00000000
--- a/web/WEB-INF/templates/guest/user/guest_registration_form.tpl
+++ /dev/null
@@ -1,108 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<ui:composition
-	xmlns="http://www.w3.org/1999/xhtml"
-	xmlns:f="http://java.sun.com/jsf/core"
-	xmlns:h="http://java.sun.com/jsf/html"
-	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
-
-	<h:form id="register_page2_form">
-		<div class="table">
-			<div class="table_header">
-				<h:outputText value="#{msg.GUEST_REGISTRATION_PAGE2_TITLE}" />
-			</div>
-
-			<ui:include src="/WEB-INF/templates/contact/form_contact_data.tpl" />
-
-			<div class="para">
-				<fieldset id="login_data">
-					<legend title="#{msg.GUEST_REGISTRATION_EMAIL_LEGEND_TITLE}">#{msg.GUEST_REGISTRATION_EMAIL_LEGEND}</legend>
-
-					<div class="table_row">
-						<div class="table_left">
-							<h:outputLabel for="userName" value="#{msg.GUEST_REGISTRATION_ENTER_USER_NAME}" />
-						</div>
-
-						<div class="table_right">
-							<h:inputText styleClass="input" id="userName" size="20" maxlength="255" value="#{userController.userName}" required="true" requiredMessage="#{msg.GUEST_REGISTRATION_USER_NAME_NOT_ENTERED}" />
-						</div>
-
-						<div class="clear"></div>
-					</div>
-
-					<h:panelGroup styleClass="error_container" layout="block">
-						<h:message for="userName" errorClass="errors" fatalClass="errors" warnClass="errors" />
-					</h:panelGroup>
-
-					<div class="table_row">
-						<div class="table_left">
-							<h:outputLabel for="emailAddress" value="#{msg.GUEST_REGISTRATION_ENTER_EMAIL1}" />
-						</div>
-
-						<div class="table_right">
-							<h:inputText styleClass="input" id="emailAddress" size="20" maxlength="255" value="#{contactController.emailAddress}" required="true" requiredMessage="#{msg.EMAIL_ADDRESS_NOT_ENTERED}" />
-						</div>
-
-						<div class="clear"></div>
-					</div>
-
-					<h:panelGroup styleClass="error_container" layout="block">
-						<h:message for="emailAddress" errorClass="errors" fatalClass="errors" warnClass="errors" />
-					</h:panelGroup>
-
-					<div class="table_row">
-						<div class="table_left">
-							<h:outputLabel for="emailAddressRepeat" value="#{msg.GUEST_REGISTRATION_ENTER_EMAIL2}" />
-						</div>
-
-						<div class="table_right">
-							<h:inputText styleClass="input" id="emailAddressRepeat" size="20" maxlength="255" value="#{contactController.emailAddressRepeat}" required="true" requiredMessage="#{msg.EMAIL_ADDRESS_REPEAT_NOT_ENTERED}" />
-						</div>
-
-						<div class="clear"></div>
-					</div>
-
-					<h:panelGroup styleClass="error_container" layout="block">
-						<h:message for="emailAddressRepeat" errorClass="errors" fatalClass="errors" warnClass="errors" />
-					</h:panelGroup>
-
-					<div class="para"></div>
-
-					<div class="table_row">
-						<div class="table_left">
-							<h:outputLabel for="userPassword" value="#{msg.GUEST_REGISTRATION_ENTER_PASSWORD}" />
-						</div>
-
-						<div class="table_right">
-							<h:inputSecret styleClass="input" id="userPassword" size="10" maxlength="255" value="#{userController.userPassword}" />
-						</div>
-
-						<div class="clear"></div>
-					</div>
-
-					<div class="table_row">
-						<div class="table_left">
-							<h:outputLabel for="userPasswordRepeat" value="#{msg.GUEST_REGISTRATION_ENTER_PASSWORD_REPEAT}" />
-						</div>
-
-						<div class="table_right">
-							<h:inputSecret styleClass="input" id="userPasswordRepeat" size="10" maxlength="255" value="#{userController.userPasswordRepeat}" />
-						</div>
-
-						<div class="clear"></div>
-					</div>
-
-					<div class="para notice">
-						<h:outputText value="#{msg.GUEST_REGISTRATION_USER_NAME_NOTICE}" />
-					</div>
-				</fieldset>
-			</div>
-
-			<ui:include src="/WEB-INF/templates/guest/guest_privacy_terms.tpl" />
-
-			<div class="table_footer">
-				<h:commandButton styleClass="reset" type="reset" value="#{msg.BUTTON_RESET_FORM}" />
-				<h:commandButton styleClass="submit" type="submit" id="register" value="#{msg.BUTTON_FINISH_REGISTRATION}" action="#{registerController.doFinishRegistration()}" />
-			</div>
-		</div>
-	</h:form>
-</ui:composition>
diff --git a/web/WEB-INF/templates/guest/user/register/guest_form_register_page1.tpl b/web/WEB-INF/templates/guest/user/register/guest_form_register_page1.tpl
index aba8452c..e53ce9ec 100644
--- a/web/WEB-INF/templates/guest/user/register/guest_form_register_page1.tpl
+++ b/web/WEB-INF/templates/guest/user/register/guest_form_register_page1.tpl
@@ -73,7 +73,15 @@
 						</h:panelGroup>
 
 						<div class="para notice">
-							<h:outputText value="#{msg.GUEST_REGISTRATION_USER_NAME_NOTICE}" />
+							<ul>
+								<li><h:outputText value="#{msg.GUEST_REGISTRATION_USER_NAME_NOTICE}" /></li>
+								<ui:fragment rendered="#{featureController.isFeatureEnabled('allow_user_registration_empty_password')}">
+									<li><h:outputText value="#{msg.GUEST_REGISTRATION_USER_PASSWORDS_EMPTY_ALLOWED}" /></li>
+								</ui:fragment>
+								<ui:fragment rendered="#{not featureController.isFeatureEnabled('allow_user_registration_empty_password')}">
+									<li><h:outputText value="#{msg.GUEST_REGISTRATION_USER_PASSWORDS_EMPTY_NOT_ALLOWED}" /></li>
+								</ui:fragment>
+							</ul>
 						</div>
 					</ui:fragment>
 				</fieldset>
diff --git a/web/WEB-INF/templates/guest/user/register/guest_form_register_single.tpl b/web/WEB-INF/templates/guest/user/register/guest_form_register_single.tpl
index 9a1dd99a..312d8ab1 100644
--- a/web/WEB-INF/templates/guest/user/register/guest_form_register_single.tpl
+++ b/web/WEB-INF/templates/guest/user/register/guest_form_register_single.tpl
@@ -75,7 +75,15 @@
 						</h:panelGroup>
 
 						<div class="para notice">
-							<h:outputText value="#{msg.GUEST_REGISTRATION_USER_NAME_NOTICE}" />
+							<ul>
+								<li><h:outputText value="#{msg.GUEST_REGISTRATION_USER_NAME_NOTICE}" /></li>
+								<ui:fragment rendered="#{featureController.isFeatureEnabled('allow_user_registration_empty_password')}">
+									<li><h:outputText value="#{msg.GUEST_REGISTRATION_USER_PASSWORDS_EMPTY_ALLOWED}" /></li>
+								</ui:fragment>
+								<ui:fragment rendered="#{not featureController.isFeatureEnabled('allow_user_registration_empty_password')}">
+									<li><h:outputText value="#{msg.GUEST_REGISTRATION_USER_PASSWORDS_EMPTY_NOT_ALLOWED}" /></li>
+								</ui:fragment>
+							</ul>
 						</div>
 					</ui:fragment>
 				</fieldset>
diff --git a/web/WEB-INF/web.xml b/web/WEB-INF/web.xml
index 4fda8ded..45ac5663 100644
--- a/web/WEB-INF/web.xml
+++ b/web/WEB-INF/web.xml
@@ -97,6 +97,11 @@
         <param-name>is_feature_user_registration_in_index_enabled</param-name>
         <param-value>false</param-value>
     </context-param>
+    <context-param>
+        <description>Whether user can leave both passwords empty on registration.</description>
+        <param-name>allow_user_registration_empty_password</param-name>
+        <param-value>false</param-value>
+    </context-param>
     <context-param>
         <description>Maximum passwords that must be different.</description>
         <param-name>max_user_password_history</param-name>
diff --git a/web/guest/user/user_register.xhtml b/web/guest/user/user_register.xhtml
index 124eefc0..9e33b2c6 100644
--- a/web/guest/user/user_register.xhtml
+++ b/web/guest/user/user_register.xhtml
@@ -19,13 +19,13 @@
 		<ui:define name="content">
 			<ui:fragment rendered="#{not featureController.isFeatureEnabled('user_registration_in_index') and featureController.isFeatureEnabled('user_registration')}">
 				<ui:fragment rendered="#{featureController.isFeatureEnabled('user_name_required')}">
-					<div class="para">
+					<h:panelGroup styleClass="para" layout="block">
 						<h:outputText value="#{msg.GUEST_ALREADY_USER_CONTINUE_LOGIN_1}" />
 						<h:outputText value="&nbsp;" />
 						<h:link outcome="user_login" value="#{msg.CLICK_HERE}" />
 						<h:outputText value="&nbsp;" />
 						<h:outputText value="#{msg.GUEST_ALREADY_USER_CONTINUE_LOGIN_2}" />
-					</div>
+					</h:panelGroup>
 				</ui:fragment>
 
 				<h:panelGroup layout="block" styleClass="registration_form">
-- 
2.39.5