diff --git a/src/main/java/org/olat/admin/user/ChangeUserPasswordForm.java b/src/main/java/org/olat/admin/user/ChangeUserPasswordForm.java
index ce524351f2c3492e7aa12c866ba687330d422567..28cf0a00c9c030513a8ea5fcbaf2188a316cba44 100644
--- a/src/main/java/org/olat/admin/user/ChangeUserPasswordForm.java
+++ b/src/main/java/org/olat/admin/user/ChangeUserPasswordForm.java
@@ -25,6 +25,8 @@
 
 package org.olat.admin.user;
 
+import static org.olat.login.ui.LoginUIFactory.formatDescriptionAsList;
+
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
@@ -34,8 +36,10 @@ import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.Identity;
 import org.olat.core.util.Util;
+import org.olat.login.auth.OLATAuthManager;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
 import org.olat.user.ChangePasswordForm;
-import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -52,10 +56,11 @@ public class ChangeUserPasswordForm extends FormBasicController {
 	
 	private String cred = "";
 
-	private Identity userIdentity;
+	private final SyntaxValidator syntaxValidator;
+	private final Identity userIdentity;
 	
 	@Autowired
-	private UserManager userManager;
+	private OLATAuthManager olatAuthManager;
 
 	/**
 	 * Constructor for user pwd forms.
@@ -67,24 +72,30 @@ public class ChangeUserPasswordForm extends FormBasicController {
 	public ChangeUserPasswordForm(UserRequest ureq, WindowControl wControl, Identity treatedIdentity) {
 		super(ureq, wControl, null, Util.createPackageTranslator(ChangePasswordForm.class, ureq.getLocale()));
 		userIdentity = treatedIdentity;
+		this.syntaxValidator = olatAuthManager.createPasswordSytaxValidator();
 		initForm(ureq);
 	}
 	
 	@Override
 	public boolean validateFormLogic (UserRequest ureq) {
+		boolean allOk = super.validateFormLogic(ureq);
 		
-		boolean newIsValid = userManager.syntaxCheckOlatPassword(pass1.getValue());
-		if (!newIsValid) pass1.setErrorKey("form.checkPassword", null);
-		
-		boolean newDoesMatch = pass1.getValue().equals(pass2.getValue());
-		if(!newDoesMatch) pass1.setErrorKey("error.password.nomatch", null);
-			
-		if (newIsValid && newDoesMatch) return true;
-		
-		pass1.setValue("");
-		pass2.setValue("");
+		pass1.clearError();
+		String newPassword = pass1.getValue();
+		ValidationResult validationResult = syntaxValidator.validate(newPassword, userIdentity);
+		if (!validationResult.isValid()) {
+			String descriptions = formatDescriptionAsList(validationResult.getInvalidDescriptions(), getLocale());
+			pass1.setErrorKey("error.password.invalid", new String[] { descriptions });
+			allOk &= false;
+		}
+
+		pass2.clearError();
+		if (!pass1.getValue().equals(pass2.getValue())) {
+			pass2.setErrorKey("error.password.nomatch", null);
+			allOk &= false;
+		}
 		
-		return false;
+		return allOk;
 	}
 
 	@Override
@@ -102,7 +113,9 @@ public class ChangeUserPasswordForm extends FormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		setFormTitle("form.password.new1");
-		setFormDescription("form.please.enter.new");
+
+		String descriptions = formatDescriptionAsList(syntaxValidator.getAllDescriptions(), getLocale());
+		setFormDescription("form.please.enter.new", new String[] { descriptions });
 		
 		TextElement username = uifactory.addTextElement("username", "form.username", 255, userIdentity.getName(), formLayout);
 		username.setEnabled(false);		
diff --git a/src/main/java/org/olat/admin/user/UserCreateController.java b/src/main/java/org/olat/admin/user/UserCreateController.java
index 45a22565e35c7437f576b21bfcf31249ad15d223..5e0687811188855dd2248f349f554509806b3c7c 100644
--- a/src/main/java/org/olat/admin/user/UserCreateController.java
+++ b/src/main/java/org/olat/admin/user/UserCreateController.java
@@ -25,10 +25,14 @@
 
 package org.olat.admin.user;
 
+import static org.olat.login.ui.LoginUIFactory.formatDescriptionAsList;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.logging.log4j.Logger;
+import org.olat.admin.user.imp.TransientIdentity;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.OrganisationRoles;
 import org.olat.basesecurity.OrganisationService;
@@ -54,13 +58,16 @@ import org.olat.core.id.Organisation;
 import org.olat.core.id.Roles;
 import org.olat.core.id.User;
 import org.olat.core.id.UserConstants;
-import org.apache.logging.log4j.Logger;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.ArrayHelper;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.i18n.I18nManager;
 import org.olat.core.util.i18n.I18nModule;
+import org.olat.login.LoginModule;
+import org.olat.login.auth.OLATAuthManager;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
 import org.olat.registration.RegistrationManager;
 import org.olat.registration.TemporaryKey;
 import org.olat.user.ChangePasswordForm;
@@ -157,6 +164,8 @@ class NewUserForm extends FormBasicController {
 	
 	private DialogBoxController confirmRemoveCtrl;
 
+	private final SyntaxValidator passwordSyntaxValidator;
+	private final SyntaxValidator usernameSyntaxValidator;
 	
 	@Autowired
 	private UserModule userModule;
@@ -165,6 +174,8 @@ class NewUserForm extends FormBasicController {
 	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
+	private OLATAuthManager olatAuthManager;
+	@Autowired
 	private RegistrationManager registrationManager;
 	@Autowired
 	private OrganisationService organisationService;
@@ -178,8 +189,11 @@ class NewUserForm extends FormBasicController {
 	 */
 	public NewUserForm(UserRequest ureq, WindowControl wControl, boolean showPasswordFields, Translator translator) {
 		super(ureq, wControl);
-		setTranslator(translator);
+		setTranslator(Util.createPackageTranslator(LoginModule.class, ureq.getLocale(), translator));
+		setTranslator(Util.createPackageTranslator(ChangePasswordForm.class, ureq.getLocale(), getTranslator()));
 		this.showPasswordFields = showPasswordFields;
+		this.passwordSyntaxValidator = olatAuthManager.createPasswordSytaxValidator();
+		this.usernameSyntaxValidator = olatAuthManager.createUsernameSytaxValidator();
 		
 		Roles managerRoles = ureq.getUserSession().getRoles();
 		if(managerRoles.isSystemAdmin()) {
@@ -243,7 +257,9 @@ class NewUserForm extends FormBasicController {
 		
 		//add password fields!!!
 		if (showPasswordFields) {
-			uifactory.addStaticTextElement("heading2", null, translate("new.form.please.enter.pwd"), formLayout);
+			String descriptions = formatDescriptionAsList(passwordSyntaxValidator.getAllDescriptions(), getLocale());
+			uifactory.addStaticTextElement("heading2", null,
+					translate("new.form.please.enter.pwd", new String[] { descriptions }), formLayout);
 
 			// checkBox: generate user with OLAT authentication or not
 			String[] authKeys = {"xx"};
@@ -253,14 +269,14 @@ class NewUserForm extends FormBasicController {
 			authCheckbox.addActionListener(FormEvent.ONCLICK);
 
 			// if OLAT authentication is used, use the pwd below
-			psw1TextElement = uifactory.addPasswordElement(FIELD_NEW1, "new.form.password.new1", 255, "", formLayout);
+			psw1TextElement = uifactory.addPasswordElement(FIELD_NEW1, "new.form.password.new1", 5000, "", formLayout);
 			psw1TextElement.setMandatory(true);
 			psw1TextElement.setDisplaySize(30);
 			psw1TextElement.setVisible(showPasswordFields);
 			psw1TextElement.setElementCssClass("o_sel_id_password1");
 			psw1TextElement.setAutocomplete("new-password");
 
-			psw2TextElement = uifactory.addPasswordElement(FIELD_NEW2, "new.form.password.new2", 255, "", formLayout);
+			psw2TextElement = uifactory.addPasswordElement(FIELD_NEW2, "new.form.password.new2", 5000, "", formLayout);
 			psw2TextElement.setMandatory(true);
 			psw2TextElement.setDisplaySize(30);		
 			psw2TextElement.setVisible(showPasswordFields);
@@ -295,21 +311,29 @@ class NewUserForm extends FormBasicController {
 	protected boolean validateFormLogic(UserRequest ureq) {
 		boolean allOk = super.validateFormLogic(ureq);
 		
+		// Transient identity for validations
+		String username = usernameTextElement.getValue();
+		TransientIdentity newIdentity = new TransientIdentity();
+		newIdentity.setName(username);
+		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
+			FormItem propertyItem = flc.getFormComponent(userPropertyHandler.getName());
+			newIdentity.setProperty(userPropertyHandler.getName(), userPropertyHandler.getStringValue(propertyItem));
+		}
+		
 		// validate if username does match the syntactical login requirements
-		String loginName = usernameTextElement.getValue();
 		usernameTextElement.clearError();
-		if (usernameTextElement.isEmpty() || !userManager.syntaxCheckOlatLogin(loginName)) {
-			usernameTextElement.setErrorKey("new.error.loginname.empty", new String[]{});
+		if (!StringHelper.containsNonWhitespace(username)) {
+			usernameTextElement.setErrorKey("form.legende.mandatory", null);
 			allOk &= false;
 		} else {
-			// Check if login is still available
-			Identity identity = securityManager.findIdentityByName(loginName);
-			if (identity != null) {
-				usernameTextElement.setErrorKey("new.error.loginname.choosen", new String[]{});
+			ValidationResult validationResult = usernameSyntaxValidator.validate(username, newIdentity);
+			if (!validationResult.isValid()) {
+				String descriptions = validationResult.getInvalidDescriptions().get(0).getText(getLocale());
+				usernameTextElement.setErrorKey("error.username.invalid", new String[] { descriptions });
 				allOk &= false;
 			}
 		}
-
+		
 		// validate special rules for each user property
 		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
 			//we assume here that there are only textElements for the user properties
@@ -347,9 +371,15 @@ class NewUserForm extends FormBasicController {
 			String pwd = psw1TextElement.getValue();
 			if(psw1TextElement.isEmpty("new.form.mandatory") || psw1TextElement.hasError()) {
 				allOk &= false;
-			} else if (!userManager.syntaxCheckOlatPassword(pwd)) {
-				psw1TextElement.setErrorKey("form.checkPassword", new String[]{});
-				allOk &=  false;
+			} else {
+				String newPassword = psw1TextElement.getValue();
+				
+				ValidationResult validationResult = passwordSyntaxValidator.validate(newPassword, newIdentity);
+				if (!validationResult.isValid()) {
+					String descriptions = formatDescriptionAsList(validationResult.getInvalidDescriptions(), getLocale());
+					psw1TextElement.setErrorKey("error.password.invalid", new String[] { descriptions });
+					allOk &= false;
+				}
 			}
 			if(psw2TextElement.isEmpty("new.form.mandatory") || psw2TextElement.hasError()) {
 				allOk &= false;
@@ -377,7 +407,7 @@ class NewUserForm extends FormBasicController {
 	
 	@Override
 	protected void formResetted(UserRequest ureq) {
-		fireEvent(ureq, Event.CANCELLED_EVENT);      
+		fireEvent(ureq, Event.CANCELLED_EVENT);
 	}
 	
 	private Identity doCreateAndPersistIdentity() {
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_ar.properties
index 82909240d0a9833a9d6afa49bdd4f5136f4698dc..1b848d62f41bd26deef4de81a0a398b94e312e49 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_ar.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_ar.properties
@@ -34,7 +34,6 @@ error.search.form.notempty=\u064A\u0631\u062C\u0649 \u0627\u0644\u0643\u062A\u06
 error.search.form.to.short=\u0643\u0644\u0645\u0629 \u0627\u0644\u0628\u062D\u062B \u0642\u0635\u064A\u0631\u0629 \u062C\u062F\u0627\u064B
 form.password.new1=\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0627\u0644\u062C\u062F\u064A\u062F\u0629
 form.password.new2=\u062A\u0623\u0643\u064A\u062F \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631
-form.please.enter.new=\u064A\u0631\u062C\u0649 \u0625\u062F\u062E\u0644 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0627\u0644\u062C\u062F\u064A\u062F\u0629 \u0644\u0647\u0630\u0627 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645
 form.token.new.text=\u0631\u0633\u0627\u0644\u0629
 form.token.new.title=\u0625\u0631\u0633\u0627\u0644 \u0631\u0627\u0628\u0637 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631
 form.username=\u0627\u0633\u0645 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645
@@ -56,7 +55,6 @@ new.form.mandatory=\u0647\u0630\u0647 \u0627\u0644\u062E\u0644\u064A\u0629 \u063
 new.form.password.new1=\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631
 new.form.password.new2=\u0627\u0644\u062A\u062D\u0642\u0642 \u0645\u0646 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631
 new.form.please.enter=\u064A\u0631\u062C\u0649 \u0625\u062F\u062E\u0627\u0644 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062A \u0627\u0644\u062A\u0627\u0644\u064A\u0629 \u0639\u0646 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645 \u0627\u0644\u062C\u062F\u064A\u062F
-new.form.please.enter.pwd=\u0627\u062E\u062A\u064A\u0627\u0631 \u0643\u0644\u0645\u0629 \u0645\u0631\u0648\u0631 \u0644\u0644\u0645\u0633\u062A\u062E\u062F\u0645 \u0627\u0644\u062C\u062F\u064A\u062F
 new.form.username=\u0627\u0633\u0645 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645
 new.user.cancel=\u062A\u0645 \u0625\u0644\u063A\u0627\u0621 \u0627\u0644\u0646\u0634\u0627\u0637\u060C \u0644\u0645 \u064A\u062A\u0645 \u0625\u0646\u0634\u0627\u0621 \u062D\u0633\u0627\u0628 \u0645\u0633\u062A\u062E\u062F\u0645 \u062C\u062F\u064A\u062F.
 new.user.successful=\u062A\u0645 \u0625\u0646\u0634\u0627\u0621 \u062D\u0633\u0627\u0628 \u0645\u0633\u062A\u062E\u062F\u0645 \u062C\u062F\u064A\u062F \u0628\u0646\u062C\u0627\u062D.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_bg.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_bg.properties
index f8e354835a590d02c18f5841fc4da6762cad9016..aa40adcc6958b466bdc24e0ff3a599e6f4087dd9 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_bg.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_bg.properties
@@ -32,7 +32,7 @@ error.password.nomatch=\u0414\u0432\u0435\u0442\u0435 \u043D\u043E\u0432\u0438 \
 error.search.form.notempty=\u041C\u043E\u043B\u044F, \u043F\u043E\u043F\u044A\u043B\u043D\u0435\u0442\u0435 \u043F\u043E\u043D\u0435 \u0435\u0434\u043D\u043E \u043E\u0442 \u0441\u044A\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430\u0449\u0438\u0442\u0435 \u043F\u043E\u043B\u0435\u0442\u0430.
 form.password.new1=\u041D\u043E\u0432\u0430 \u043F\u0430\u0440\u043E\u043B\u0430
 form.password.new2=\u041F\u043E\u0442\u0432\u044A\u0440\u0434\u0435\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u0430
-form.please.enter.new=\u041C\u043E\u043B\u044F, \u043D\u0430\u043F\u0438\u0448\u0435\u0442\u0435 \u043D\u043E\u0432\u0430 \u043F\u0430\u0440\u043E\u043B\u0430 \u0437\u0430 \u0442\u043E\u0437\u0438 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B
+form.please.enter.new=\u041C\u043E\u043B\u044F, \u043D\u0430\u043F\u0438\u0448\u0435\u0442\u0435 \u043D\u043E\u0432\u0430 \u043F\u0430\u0440\u043E\u043B\u0430 \u0437\u0430 \u0442\u043E\u0437\u0438 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B.{0}
 form.username=\u041F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E \u0438\u043C\u0435
 found.property=\u0418\u0437\u0431\u0440\u0430\u043D\u0430 \u0445\u0430\u0440\u0430\u043A\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043A\u0430 {0}
 header.autocompletion=\u0422\u044A\u0440\u0441\u0435\u0442\u0435 \u0432 \u043A\u043E\u043C\u0431\u0438\u043D\u0430\u0446\u0438\u044F \u0441 \u0430\u0432\u0442\u043E-\u043F\u043E\u043F\u044A\u043B\u0432\u0430\u043D\u0435
@@ -52,7 +52,7 @@ new.form.mandatory=\u0422\u043E\u0432\u0430 \u0435 \u0437\u0430\u0434\u044A\u043
 new.form.password.new1=\u041F\u0430\u0440\u043E\u043B\u0430
 new.form.password.new2=\u041F\u043E\u0442\u0432\u044A\u0440\u0434\u0435\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u0430
 new.form.please.enter=\u041C\u043E\u043B\u044F, \u043D\u0430\u043F\u0438\u0448\u0435\u0442\u0435 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u0437\u0430 \u043D\u043E\u0432 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B
-new.form.please.enter.pwd=\u0418\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u0430 \u0437\u0430 \u043D\u043E\u0432 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B
+new.form.please.enter.pwd=\u0418\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u0430 \u0437\u0430 \u043D\u043E\u0432 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B.{0}
 new.form.username=\u041F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E \u0438\u043C\u0435
 new.user.cancel=\u041E\u043F\u0435\u0440\u0430\u0446\u0438\u044F\u0442\u0430 \u0435 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430. \u041D\u0435 \u0435 \u0441\u044A\u0437\u0434\u0430\u0434\u0435\u043D \u043D\u043E\u0432 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u0438 \u0430\u043A\u0430\u0443\u043D\u0442.
 new.user.successful=\u041D\u043E\u0432\u0438\u044F\u0442 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u0438 \u0430\u043A\u0430\u0443\u043D\u0442 \u0435 \u0441\u044A\u0437\u0434\u0430\u0434\u0435\u043D \u0443\u0441\u043F\u0435\u0448\u043D\u043E.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_cs.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_cs.properties
index 4c79abb4f3c05f0ca53a17438b6f073a10243e7d..cb15c20ad5ebda8c97ab7b2e6186f551cfc991f9 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_cs.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_cs.properties
@@ -29,7 +29,7 @@ error.password.nomatch=Vlo\u017Een\u00E1 hesla nejsou toto\u017En\u00E1.
 error.search.form.notempty=Pros\u00EDm, vypl\u0148te alespo\u0148 jedno z dostupn\u00FDch pol\u00ED.
 form.password.new1=Nov\u00E9 heslo
 form.password.new2=Potvrdit heslo
-form.please.enter.new=Pros\u00EDm vlo\u017Ete nov\u00E9 heslo u\u017Eivatele
+form.please.enter.new=Pros\u00EDm vlo\u017Ete nov\u00E9 heslo u\u017Eivatele.{0}
 form.username=U\u017Eivatelsk\u00E9 jm\u00E9no
 found.property=Vybran\u00FD parametr {0}
 header.autocompletion=Vyhled\u00E1v\u00E1n\u00ED kombinovan\u00E9 s automatick\u00FDm dokon\u010Dov\u00E1n\u00EDm
@@ -49,7 +49,7 @@ new.form.mandatory=Toto pole je povinn\u00E9, vlo\u017Ete pros\u00EDm hodnotu\!
 new.form.password.new1=Heslo
 new.form.password.new2=Ov\u011B\u0159en\u00ED hesla
 new.form.please.enter=Pros\u00EDm vlo\u017Ete informace o nov\u00E9m u\u017Eivateli 
-new.form.please.enter.pwd=Vyberte pro nov\u00E9ho u\u017Eivatele heslo
+new.form.please.enter.pwd=Vyberte pro nov\u00E9ho u\u017Eivatele heslo.{0}
 new.form.username=U\u017Eivatelsk\u00E9 jm\u00E9no
 new.user.cancel=Akce byla zru\u0161ena. Nov\u00FD \u00FA\u010Det nebyl vytvo\u0159en.
 new.user.successful=Nov\u00FD u\u017Eivatelsk\u00FD \u00FA\u010Det byl \u00FAsp\u011B\u0161n\u011B vytvo\u0159en.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_da.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_da.properties
index 38a43c836b0d04b0ef510e449bf153d255b11779..251281f2a05571691272d6a13e02ffce1c688549 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_da.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_da.properties
@@ -24,7 +24,7 @@ error.password.nomatch=De indtastede kodeord passer ikke sammen.
 error.search.form.notempty=Udfyld venligst et af de tilg\u00E6ngelige felter
 form.password.new1=Nyt kodeord
 form.password.new2=Bekr\u00E6ft kodeord
-form.please.enter.new=Indtast venligst et nyt kodeord for denne bruger 
+form.please.enter.new=Indtast venligst et nyt kodeord for denne bruger.{0}
 form.username=Brugernavn
 found.property=Egenskab valgt {0}
 header.autocompletion=S\u00F8gning kombineret med auto-completion
@@ -41,7 +41,7 @@ new.form.language=Sprog
 new.form.password.new1=Kodeord
 new.form.password.new2=Bekr\u00E6ft kodeord
 new.form.please.enter=Indtast venligst information om den nye bruger
-new.form.please.enter.pwd=V\u00E6lg et kodeord for den nye bruger
+new.form.please.enter.pwd=V\u00E6lg et kodeord for den nye bruger.{0}
 new.form.username=Brugernavn
 new.user.cancel=Handlingen er afbrudt. Ingen ny konto er oprettet.
 new.user.successful=Den nye brugerkonto er oprettet succesfult.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
index 823b0f9907e85c179a122ee1100f33658d5da0c5..d8d4779799b1af3008b67453e0df33bc9b9e9d73 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
@@ -53,7 +53,7 @@ export.user.data=Daten exportieren
 export.user.data.title=Benutzerdaten von "{0}" exportieren
 form.password.new1=Neues Passwort
 form.password.new2=Passwort best\u00E4tigen
-form.please.enter.new=Bitte geben Sie das neue Passwort f\u00FCr diesen Benutzer ein.
+form.please.enter.new=Bitte geben Sie das neue Passwort f\u00FCr diesen Benutzer ein.{0}
 form.token.new.description=Mit Hilfe der Schaltfl\u00E4che "Passwortlink senden" erstellen Sie einen Passwortlink und senden diesen direkt per Mail an den Benutzer. Mit einem Klick darauf wird das alte Passwort zur\u00FCckgesetzt und der Benutzer kann ein neues Passwort eingeben.
 form.token.new.text=Nachricht
 form.token.new.title=Passwortlink senden f\u00FCr OpenOLAT Passwort
@@ -81,7 +81,7 @@ new.form.organisations=Organisation
 new.form.password.new1=Passwort
 new.form.password.new2=Passwort verifizieren
 new.form.please.enter=Angaben zur Person des neuen Benutzerkontos
-new.form.please.enter.pwd=Setzen Sie dem Benutzer ein Passwort.
+new.form.please.enter.pwd=Setzen Sie dem Benutzer ein Passwort.{0}
 new.form.username=Benutzername
 new.user.cancel=Die Aktion wurde abgebrochen. Es wurde keine neues Benutzerkonto angelegt.
 new.user.successful=Das neue Benutzerkonto wurde angelegt.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_el.properties
index 699e4158fe20b2efbfded1c8b95b8d74c72e3963..c76defe04a85cd6760f78b59a876d4aa99f718ff 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_el.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_el.properties
@@ -35,7 +35,7 @@ error.search.form.notempty=\u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03BF\u03C
 error.search.form.to.short=\u03A0\u03BF\u03BB\u03CD \u03BC\u03B9\u03BA\u03C1\u03CC\u03C2 \u03CC\u03C1\u03BF\u03C2 \u03B1\u03BD\u03B1\u03B6\u03AE\u03C4\u03B7\u03C3\u03B7\u03C2.
 form.password.new1=\u039D\u03AD\u03BF\u03C2 \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2
 form.password.new2=\u0395\u03C0\u03B9\u03B2\u03B5\u03B2\u03B1\u03AF\u03C9\u03C3\u03B7 \u03BA\u03C9\u03B4\u03B9\u03BA\u03BF\u03CD \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2
-form.please.enter.new=\u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03BF\u03CD\u03BC\u03B5 \u03B5\u03B9\u03C3\u03AC\u03B3\u03B5\u03C4\u03B5 \u03AD\u03BD\u03B1 \u03BD\u03AD\u03BF \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03B3\u03B9\u03B1 \u03C4\u03BF \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7
+form.please.enter.new=\u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03BF\u03CD\u03BC\u03B5 \u03B5\u03B9\u03C3\u03AC\u03B3\u03B5\u03C4\u03B5 \u03AD\u03BD\u03B1 \u03BD\u03AD\u03BF \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03B3\u03B9\u03B1 \u03C4\u03BF \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7.{0}
 form.token.new.text=\u039C\u03AE\u03BD\u03C5\u03BC\u03B1
 form.username=\u038C\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7
 found.property=\u0397 \u03B9\u03B4\u03B9\u03CC\u03C4\u03B7\u03C4\u03B1 \u03B5\u03C0\u03B9\u03BB\u03AD\u03C7\u03C4\u03B7\u03BA\u03B5
@@ -56,7 +56,7 @@ new.form.mandatory=\u03A4\u03BF \u03C0\u03B5\u03B4\u03AF\u03BF \u03B5\u03AF\u03B
 new.form.password.new1=\u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2
 new.form.password.new2=\u0395\u03C0\u03B9\u03B2\u03B5\u03B2\u03B1\u03AF\u03C9\u03C3\u03B7 \u03BA\u03C9\u03B4\u03B9\u03BA\u03BF\u03CD
 new.form.please.enter=\u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03B5\u03B9\u03C3\u03AC\u03B3\u03B5\u03C4\u03B5 \u03C4\u03B9\u03C2 \u03C0\u03BB\u03B7\u03C1\u03BF\u03C6\u03BF\u03C1\u03AF\u03B5\u03C2 \u03B3\u03B9\u03B1 \u03C4\u03BF \u03BD\u03AD\u03BF \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7
-new.form.please.enter.pwd=\u0395\u03C0\u03B9\u03BB\u03AD\u03BE\u03C4\u03B5 \u03AD\u03BD\u03B1 \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03B3\u03B9\u03B1 \u03C4\u03BF \u03BD\u03AD\u03BF \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7
+new.form.please.enter.pwd=\u0395\u03C0\u03B9\u03BB\u03AD\u03BE\u03C4\u03B5 \u03AD\u03BD\u03B1 \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03B3\u03B9\u03B1 \u03C4\u03BF \u03BD\u03AD\u03BF \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7.{0}
 new.form.username=\u038C\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7
 new.user.cancel=\u0397 \u03B5\u03BD\u03AD\u03C1\u03B3\u03B5\u03B9\u03B1 \u03B1\u03BA\u03C5\u03C1\u03CE\u03B8\u03B7\u03BA\u03B5. \u039F \u03BD\u03AD\u03BF\u03C2 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4\u03B5\u03BD \u03B4\u03B7\u03BC\u03B9\u03BF\u03C5\u03C1\u03B3\u03AE\u03B8\u03B7\u03BA\u03B5.
 new.user.successful=\u039F \u03BD\u03AD\u03BF\u03C2 \u03BB\u03BF\u03B3\u03B1\u03C1\u03B9\u03B1\u03C3\u03BC\u03CC\u03C2 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03B4\u03B7\u03BC\u03B9\u03BF\u03C5\u03C1\u03B3\u03AE\u03B8\u03B7\u03BA\u03B5 \u03BC\u03B5 \u03B5\u03C0\u03B9\u03C4\u03C5\u03C7\u03AF\u03B1.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
index 2772dd8d09bef62ec16ab535205dfb46fafff17b..d2a085a92268338a23bb7ba2155b75c5a6a738a2 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
@@ -53,7 +53,7 @@ export.user.data=Export data
 export.user.data.title=Export user data of "{0}"
 form.password.new1=New password
 form.password.new2=Confirm password
-form.please.enter.new=Please enter a new password for this user
+form.please.enter.new=Please enter a new password for this user.{0}
 form.token.new.description=By means of the button "Send password link" you can create a password link and send it via e-mail to your user. When clicking on it an old password will be reset allowing your user to set a new one.
 form.token.new.text=Message
 form.token.new.title=Send password link for OpenOLAT password
@@ -81,7 +81,7 @@ new.form.organisations=Organisation
 new.form.password.new1=Password
 new.form.password.new2=Verify password
 new.form.please.enter=Please enter information on new user
-new.form.please.enter.pwd=Choose a password for new user
+new.form.please.enter.pwd=Choose a password for the new user.{0}
 new.form.username=User name
 new.user.cancel=Action cancelled. No new user account created.
 new.user.successful=The new user account has been created successfully.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_es.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_es.properties
index 492ad7fa2a8e08a233637a79aea8c749330f3059..20b20a480cba3667a1a1a2378c63ecad8a2e29bd 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_es.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_es.properties
@@ -30,7 +30,7 @@ error.password.nomatch=Las dos nuevas contrase\u00F1as no coinciden.
 error.search.form.notempty=Por favor rellena al menos una de las casillas disponibles.
 form.password.new1=Nueva contrase\u00F1a
 form.password.new2=Confirmar contrase\u00F1a
-form.please.enter.new=Por favor introduce la nueva contrase\u00F1a para este usuario
+form.please.enter.new=Por favor introduce la nueva contrase\u00F1a para este usuario.{0}
 form.username=Nombre de usuario
 found.property=Propiedad seleccionada {0}
 header.autocompletion=Buscar con auto-completamiento
@@ -50,7 +50,7 @@ new.form.mandatory=\u00A1Esta es una casilla requerida, por favor introduzca un
 new.form.password.new1=Contrase\u00F1a
 new.form.password.new2=Confirmar contrase\u00F1a
 new.form.please.enter=Por favor introduce la informaci\u00F3n del nuevo usuario
-new.form.please.enter.pwd=Selecciona una contrase\u00F1a para el nuevo usuario
+new.form.please.enter.pwd=Selecciona una contrase\u00F1a para el nuevo usuario.{0}
 new.form.username=Nombre de usuario 
 new.user.cancel=Acci\u00F3n cancelada. No se cre\u00F3 la nueva cuenta de usuario.
 new.user.successful=La nueva cuenta de usuario se cre\u00F3 correctamente.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fa.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fa.properties
index 970405f3153ea90ab93bb72d5948898537c900c6..f17cfbb4e9201d531087fb51e3ae65fa3b7885b6 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fa.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fa.properties
@@ -23,7 +23,6 @@ error.password.nomatch=\u062F\u0648 \u06A9\u0644\u0645\u0647 \u0639\u0628\u0648\
 error.search.form.notempty=\u0644\u0637\u0641\u0627\u064B \u062D\u062F\u0627\u0642\u0644 \u06CC\u06A9\u06CC \u0627\u0632 \u0641\u06CC\u0644\u062F\u0647\u0627 \u0631\u0627 \u067E\u0631 \u06A9\u0646 
 form.password.new1=\u06A9\u0644\u0645\u0647 \u0639\u0628\u0648\u0631 \u062C\u062F\u06CC\u062F
 form.password.new2=\u062A\u0627\u06CC\u06CC\u062F \u06A9\u0644\u0645\u0647 \u0639\u0628\u0648\u0631 
-form.please.enter.new=\u0644\u0637\u0641\u0627\u064B \u06A9\u0644\u0645\u0647 \u0639\u0628\u0648\u0631 \u062C\u062F\u06CC\u062F \u0628\u0631\u0627\u06CC \u0627\u06CC\u0646 \u06A9\u0627\u0631\u0628\u0631 \u0627\u0646\u062A\u062E\u0627\u0628 \u0646\u0645\u0627\u06CC\u06CC\u062F 
 form.username=\u0646\u0627\u0645 \u06A9\u0627\u0631\u0628\u0631 
 found.property=\u0645\u0634\u062E\u0635\u0647 \u0627\u0646\u062A\u062E\u0627\u0628 \u0634\u062F 
 mailto.userlist=\u0644\u06CC\u0633\u062A \u06A9\u0627\u0631\u0628\u0631\u0627\u0646 
@@ -38,7 +37,6 @@ new.form.language=\u0632\u0628\u0627\u0646
 new.form.password.new1=\u06A9\u0644\u0645\u0647 \u0639\u0628\u0648\u0631 
 new.form.password.new2=\u0634\u0646\u0627\u0633\u0627\u06CC\u06CC \u06A9\u0644\u0645\u0647 \u0639\u0628\u0648\u0631 
 new.form.please.enter=\u0644\u0637\u0641\u0627\u064B \u0627\u0637\u0644\u0627\u0639\u0627\u062A \u06A9\u0627\u0631\u0628\u0631 \u062C\u062F\u06CC\u062F \u0631\u0627 \u0648\u0627\u0631\u062F \u0646\u0645\u0627\u06CC\u06CC\u062F 
-new.form.please.enter.pwd=\u0627\u0646\u062A\u062E\u0627\u0628 \u06A9\u0644\u0645\u0647 \u0639\u0628\u0648\u0631 \u0628\u0631\u0627\u06CC \u06A9\u0627\u0631\u0628\u0631 \u062C\u062F\u06CC\u062F
 new.form.username=\u0646\u0627\u0645 \u06A9\u0627\u0631\u0628\u0631 
 new.user.cancel=\u0639\u0645\u0644\u06CC\u0627\u062A \u0644\u063A\u0648 \u06AF\u0631\u062F\u06CC\u062F / \u0647\u06CC\u0686 \u06A9\u0627\u0631\u0628\u0631\u06CC \u0627\u06CC\u062C\u0627\u062F \u0646\u06AF\u0631\u062F\u06CC\u062F
 new.user.successful=\u062D\u0633\u0627\u0628 \u06A9\u0627\u0631\u0628\u0631 \u062C\u062F\u06CC\u062F \u0628\u0627 \u0645\u0648\u0641\u0642\u06CC\u062A \u0627\u06CC\u062C\u0627\u062F \u06AF\u0631\u062F\u06CC\u062F 
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fr.properties
index a59027cedfd07c8c1a85ae1d595ca07fb786700e..3c40c864aa7b5b59172ee6ad25b892686bac0957 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_fr.properties
@@ -53,7 +53,7 @@ export.user.data=Exporter les donn\u00E9es
 export.user.data.title=Exporter les donn\u00E9es utilisateurs de "{0}"
 form.password.new1=Nouveau mot de passe
 form.password.new2=Confirmer mot de passe 
-form.please.enter.new=Veuillez ins\u00E9rer le nouveaux mot de passe pour cet utilisateur s.v.p. 
+form.please.enter.new=Veuillez ins\u00E9rer le nouveaux mot de passe pour cet utilisateur s.v.p.{0}
 form.token.new.description=Gr\u00E2ce au bouton "Envoyer lien mot de passe", vous pouvez cr\u00E9er un lien pour le mot de passe et l'envoyer \u00E0 l'utilisateur par e-mail. En cliquant dessus, l'utilisateur peut introduire un nouveau mot de passe (l'ancien mot de passe sera annul\u00E9).
 form.token.new.text=Message
 form.token.new.title=Envoyer lien mot de passe
@@ -81,7 +81,7 @@ new.form.organisations=Organisation
 new.form.password.new1=Mot de passe
 new.form.password.new2=V\u00E9rifier mot de passe
 new.form.please.enter=Informations sur la personne du nouveau compte utilisateur
-new.form.please.enter.pwd=Attribuez un mot de passe \u00E0 l'utilisateur
+new.form.please.enter.pwd=Attribuez un mot de passe \u00E0 l'utilisateur.{0}
 new.form.username=Nom d'utilisateur
 new.user.cancel=L'action a \u00E9t\u00E9 annul\u00E9e. Aucun nouveau compte utilisateur n'a \u00E9t\u00E9 cr\u00E9\u00E9.
 new.user.successful=Le nouveau compte utilisateur a \u00E9t\u00E9 cr\u00E9\u00E9.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_it.properties
index 167ac1b5a81995837c56154e8d0c5e2b0d6180c2..2475d12b38928edf9ac75751aa2845e4c3290411 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_it.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_it.properties
@@ -40,7 +40,7 @@ error.search.form.to.short=Termine di ricerca troppo corto.
 error.search.maxResults=Troppi risultati trovati. Solo i primi {0} risultati sono mostrati.
 form.password.new1=Nuova password
 form.password.new2=Conferma la password
-form.please.enter.new=Inserisca la nuova password per questo utente, p.f.
+form.please.enter.new=Inserisca la nuova password per questo utente, p.f.{0}
 form.token.new.description=Mediante il pulsante "Inviare link password" pu\u00F2 creare un link per la password e inviarlo all'utente via e-mail. Cliccandolo, l'utente pu\u00F2 immettere una nuova password (la vecchia password viene annullata).
 form.token.new.text=Messaggio
 form.token.new.title=Inviare link password
@@ -65,7 +65,7 @@ new.form.mandatory=Questa \u00E8 una casella obbligatoria, inserisca un valore,
 new.form.password.new1=Password
 new.form.password.new2=Conferma la password
 new.form.please.enter=Indicazioni sulla persona relativa al nuovo conto utente
-new.form.please.enter.pwd=Stabilisca una password per l'utente. 
+new.form.please.enter.pwd=Stabilisca una password per l'utente.{0}
 new.form.username=Nome utente
 new.user.cancel=L'azione \u00E8 stata interrotta. Nessun nuovo conto utente \u00E8 stato creato.
 new.user.successful=Il nuovo conto utente \u00E8 stato creato.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_jp.properties
index f3cba975419133ab0604adce705e5131367928e2..b3ba2e649f0dc5e45600416a5ecd2fa8cec0aa9e 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_jp.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_jp.properties
@@ -36,7 +36,6 @@ error.search.form.notempty=\u5C11\u306A\u304F\u3068\u30821\u3064\u306E\u6709\u52
 error.search.form.to.short=\u691C\u7D22\u30AD\u30FC\u30EF\u30FC\u30C9\u304C\u77ED\u3059\u304E\u307E\u3059\u3002
 form.password.new1=\u65B0\u3057\u3044\u30D1\u30B9\u30EF\u30FC\u30C9
 form.password.new2=\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u3082\u3046\u4E00\u5EA6
-form.please.enter.new=\u3053\u306E\u30E6\u30FC\u30B6\u306E\u65B0\u3057\u3044\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002
 form.token.new.text=\u30E1\u30C3\u30BB\u30FC\u30B8
 form.token.new.title=\u30D1\u30B9\u30EF\u30FC\u30C9\u30EA\u30F3\u30AF\u3092\u9001\u4FE1\u3059\u308B
 form.username=\u30E6\u30FC\u30B6\u540D
@@ -58,7 +57,6 @@ new.form.mandatory=\u3053\u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u306F\u3001\u5FC5\
 new.form.password.new1=\u30D1\u30B9\u30EF\u30FC\u30C9
 new.form.password.new2=\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u3082\u3046\u4E00\u5EA6
 new.form.please.enter=\u65B0\u3057\u3044\u30E6\u30FC\u30B6\u306E\u60C5\u5831\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002
-new.form.please.enter.pwd=\u65B0\u3057\u3044\u30E6\u30FC\u30B6\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002
 new.form.username=\u30E6\u30FC\u30B6\u540D
 new.user.cancel=\u51E6\u7406\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F\u3002\u65B0\u3057\u3044\u30E6\u30FC\u30B6\u306F\u3001\u4F5C\u6210\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F\u3002
 new.user.successful=\u65B0\u3057\u3044\u30E6\u30FC\u30B6\u30A2\u30AB\u30A6\u30F3\u30C8\u304C\u6B63\u5E38\u306B\u4F5C\u6210\u3055\u308C\u307E\u3057\u305F\u3002
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_lt.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_lt.properties
index d546e5659def21ee3c71aec37d697b47e7c1dd88..224f6ac414e4dcadd6043f98e8e5ab3015bec98a 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_lt.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_lt.properties
@@ -23,7 +23,7 @@ error.password.nomatch=Slapta\u017Eod\u017Eiai nesutampa.
 error.search.form.notempty=Pra\u0161ome u\u017Epildyti bent vien\u0105 lauk\u0105.
 form.password.new1=Naujas slapta\u017Eodis
 form.password.new2=Pakartoti slapta\u017Eod\u012F
-form.please.enter.new=Pra\u0161ome \u0161iam naudotojui \u012Fvesti nauj\u0105 slapta\u017Eod\u012F
+form.please.enter.new=Pra\u0161ome \u0161iam naudotojui \u012Fvesti nauj\u0105 slapta\u017Eod\u012F.{0}
 form.username=Naudotojo vardas
 found.property=Savyb\u0117 pasirinkta {0}
 mailto.userlist=Naudotoj\u0173 s\u0105ra\u0161as
@@ -38,7 +38,7 @@ new.form.language=Kalba
 new.form.password.new1=Slapta\u017Eodis
 new.form.password.new2=Pakartoti slapta\u017Eod\u012F
 new.form.please.enter=Pra\u0161ome \u012Fvesti naujo naudotojo duomenis
-new.form.please.enter.pwd=\u012Eveskite naujo naudotojo slapta\u017Eod\u012F
+new.form.please.enter.pwd=\u012Eveskite naujo naudotojo slapta\u017Eod\u012F.{0}
 new.form.username=Naudotojo vardas
 new.user.cancel=Veiksmas buvo at\u0161auktas. Naujas naudotojas nesukurtas.
 new.user.successful=Naujas naudotojas s\u0117kmingai sukurtas
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_nl_NL.properties
index 76619cbfe9774c9e77444357ef491b674a816ea4..57b6c626e52388b8f6e221747cc2f9a7aa9df845 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_nl_NL.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_nl_NL.properties
@@ -36,7 +36,7 @@ error.search.form.notempty=Gelieve ten minste \u00E9\u00E9n veld in te vullen.
 error.search.form.to.short=Zoekterm is te kort.
 form.password.new1=Nieuw wachtwoord
 form.password.new2=Wachtwoord bevestigen
-form.please.enter.new=Gelieve een nieuw wachtwoord voor deze gebruiker in te geven
+form.please.enter.new=Gelieve een nieuw wachtwoord voor deze gebruiker in te geven.{0}
 form.token.new.description=Doormiddel van de knop "Verstuur wachtwoord link" kunt u een wachtwoord link aanmaken en het via e-mail versturen naar uw gebruiker. Door er op te klikken wordt het oud wachtwoord reset waardoor uw gebruiker een nieuw wachtwoord kan instellen.
 form.token.new.text=Bericht
 form.token.new.title=Verstuur wachtwoord link
@@ -59,7 +59,7 @@ new.form.mandatory=Dit veld is verplicht.
 new.form.password.new1=Wachtwoord
 new.form.password.new2=Wachtwoord verifi\u00EBren
 new.form.please.enter=Gelieve informatie over nieuwe gebruiker in te geven
-new.form.please.enter.pwd=Kies een wachtwoord voor een nieuwe gebruiker
+new.form.please.enter.pwd=Kies een wachtwoord voor een nieuwe gebruiker.{0}
 new.form.username=Gebruikersnaam
 new.user.cancel=Actie geannuleerd. Geen nieuw gebruikersaccount aangemaakt.
 new.user.successful=Het nieuwe gebruikersaccount werd met succes aangemaakt.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pl.properties
index 15548520a353cb22dc19b6c265d74e2b60038b67..f4cba13271ff45f1551ee1bd19d79893c6a1e3d0 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pl.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pl.properties
@@ -37,7 +37,7 @@ error.search.form.to.short=Podana fraza jest zbyt kr\u00F3tka
 error.search.maxResults=Znaleziono zbyt du\u017Cy wynik\u00F3w. Tylko pierwsze {0} z nich zostan\u0105 wy\u015Bwietlone.
 form.password.new1=Nowe has\u0142o
 form.password.new2=Potwierd\u017A nowe has\u0142o
-form.please.enter.new=Wprowad\u017A nowe has\u0142o dla tego u\u017Cytkownika
+form.please.enter.new=Wprowad\u017A nowe has\u0142o dla tego u\u017Cytkownika.{0}
 form.token.new.description=U\u017Cywaj\u0105c przycisku "Wy\u015Blij link resetowania has\u0142a", utworzysz link, kt\u00F3ry zostanie wys\u0142any mailem do u\u017Cytkownika. Za jego pomoc\u0105, mo\u017Cliwe b\u0119dzie zresetowanie starego has\u0142a i utworzenie nowego.
 form.token.new.text=Wiadomo\u015B\u0107
 form.token.new.title=Wy\u015Blij link resetowania has\u0142a
@@ -60,7 +60,7 @@ new.form.mandatory=Pole obowi\u0105zkowe, wpisz warto\u015B\u0107\!
 new.form.password.new1=Has\u0142o
 new.form.password.new2=Potwierd\u017A has\u0142o
 new.form.please.enter=Prosz\u0119 poda\u0107 informacje o nowym u\u017Cytkowniku.
-new.form.please.enter.pwd=Wybierz has\u0142o dla nowego u\u017Cytkownika
+new.form.please.enter.pwd=Wybierz has\u0142o dla nowego u\u017Cytkownika.{0}
 new.form.username=Nazwa u\u017Cytkownika
 new.user.cancel=Akcj\u0119 anulowano. Brak nowych kont u\u017Cytkownika.
 new.user.successful=Nowe konto u\u017Cytkownika zosta\u0142o utworzone.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_BR.properties
index 9023c8fa29442b26e52ef3d799bb8143b1041962..438eb2a0101a500a40b1f5be9b0f4b3daabe418b 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_BR.properties
@@ -1,11 +1,8 @@
 #Thu May 23 15:11:49 CEST 2019
 action.bulkedit=Editar os atributos desses usu\u00E1rios
-action.choose=Choose
 action.choose.finish=Fechar e terminar
 action.select=Selecionar
 admins=Administrador
-authedit.delete.confirm=Are you sure you want to delete the authentication provider {0} for user {1}?
-authedit.delete.success=Authentication provider {0} deleted for user {1}.
 authors=Autor
 autocomplete.noresults=$org.olat.core.gui.control.generic.ajax.autocompletion\:autocomplete.noresults
 autocompletion.info=Pesquisa por login, primeiro nome, \u00FAltimo nome, e-mail ou matr\u00EDcula (n\u00FAmero de registro)
@@ -15,11 +12,9 @@ bulkChange.failed=Nenhuma modifica\u00E7\u00E3o feita
 bulkChange.partialsuccess={0} de {1} modifica\u00E7\u00F5es sucedidas. Os seguintes atributos de usu\u00E1rio n\u00E3o poderam ser modificados\: {3}
 bulkChange.success=Modifica\u00E7\u00E3o completada com sucesso
 bulkChange.title=Modifica\u00E7\u00E3o de atributos de usu\u00E1rio
-changeuserpwd.cancel=Action was cancelled. Password remains unchanged.
 changeuserpwd.failed=Sua nova senha n\u00E3o pode ser salva. Houve um erro inesperado no servidor.
 changeuserpwd.successful=New password saved successfully. It is valid from now on.
 clear=Limpar
-command.mail=Send e-mail to these users
 confirm.clear.identity=Deseja realmente limpar o nome e sobrenome desse usu\u00E1rio exclu\u00EDdo "{0}"?
 content.usermgmt.text1=Aqui voc\u00EA pode modificar ou gerenciar dados de usu\u00E1rios existentes do OLAT. Favor iniciar sua busca de usu\u00E1rio.
 content.usermgmt.title=Gerenciamento do usu\u00E1rio
@@ -28,20 +23,10 @@ delete.pending.registration.confirmation=Existe um auto-registro pendente para o
 delete.pending.registration.confirmation.title=Excluir auto registro
 deleted.user.list=Lista de usu\u00E1rios exclu\u00EDdos
 deselectall=$org.olat.core.gui.components.table\:uncheckall
-edit.uauth=Authentications
 edit.uhomepage=Cart\u00E3o de visitas
-edit.uprefs=System settings
-edit.uprofile=User profile
-edit.uprop=Properties
-edit.upwd=Change password
-edit.uquota=Quota
 edit.urelations=Rela\u00E7\u00F5es
-edit.uroles=Roles
 email.notsent=$org.olat.user\:email.notsent
 email.sent=$org.olat.user\:email.sent
-error.no.user.found=No user was found with these attributes. Please try again.
-error.noaccess.to.user=You do not have enough rights to edit this user. Please contact {0}.
-error.password.nomatch=The two new passwords do not match.
 error.roles.atleastone=Pelo menos um papel \u00E9 obrigat\u00F3rio
 error.roles.atleastone.userorinvitee=Pelo menos uma fun\u00E7\u00E3o "$\:role.user" ou "$\:role.invitee" \u00E9 obrigat\u00F3ria.
 error.search.form.no.valid.datechooser=Por favor, indique uma data v\u00E1lida.
@@ -51,13 +36,9 @@ error.search.form.to.short=Termo de pesquisa muito curto.
 error.search.maxResults=Muitos resultados encontrados. Apenas o primeiro {0} s\u00E3o exibidos.
 export.user.data=Exportar dados
 export.user.data.title=Exportar dados do usu\u00E1rio "{0}"
-form.password.new1=New password
-form.password.new2=Confirm password
-form.please.enter.new=Please enter a new password for this user
 form.token.new.description=Atrav\u00E9s do bot\u00E3o "Enviar link da senha" voc\u00EA pode criar um link de senha e envi\u00E1-lo via e-mail para o usu\u00E1rio. Ao clicar sobre ele a senha antiga ser\u00E1 exclu\u00EDda permitindo que seu usu\u00E1rio defina uma nova.
 form.token.new.text=Mensagem
 form.token.new.title=Enviar link de senha
-form.username=User name
 found.property=Property selected
 groupmanagers=Gestor de grupo
 header.autocompletion=Busca combinada com auto-completar
@@ -65,22 +46,15 @@ header.normal=Pesquisa com atributos de usu\u00E1rio
 instoresmanager=Gestor de recurso did\u00E1tico
 mailtemplate.login.denied.body=Sua conta OpenOLAT {0} com o endere\u00E7o de e-mail {1} est\u00E1 bloqueada.\r\n\r\n\r\nSe voc\u00EA n\u00E3o concorda com esta mudan\u00E7a, por favor, contate o suporte imediatamente em {3}.
 mailtemplate.login.denied.subject=Conta OpenOLAT bloqueada
-mailto.userlist=List of users
 msg.selectionempty=Favor selecione pelo menos um usu\u00E1rio.
-new.error.email.choosen=This e-mail address already exists. There is no need to create another account for this user. No data saved.
-new.error.loginname.choosen=This user name has already been allocated. Please try another one.
 new.error.loginname.empty=$org.olat.user\:form.checkUsername
-new.error.password.nomatch=The two passwords do not match.
 new.error.property.invalid=Entrada invalida\!
 new.form.auth=OLAT password
-new.form.auth.false=Do not create now
-new.form.auth.true=Create now
-new.form.language=Language
 new.form.mandatory=Campo obrigat\u00EDrio, entrar com um valor\!
 new.form.organisations=Organiza\u00E7\u00E3o
 new.form.password.new1=Password
 new.form.password.new2=Verify password
-new.form.please.enter=Please enter information on new user 
+new.form.please.enter=Please enter information on new user
 new.form.please.enter.pwd=Choose a password for new user
 new.form.username=User name
 new.user.cancel=Action cancelled. No new user account created.
@@ -92,14 +66,10 @@ notification.noSubscription=Voc\u00EA n\u00E3o est\u00E1 inscrito para receber n
 owner=Propriet\u00E1rio do Curso
 poolsmanager=Gestor do banco de perguntas
 repocoach=Coach de Curso
-rightForm.error.anonymous.no.roles=Anonymous guests can not exercise system roles
 rightsForm.add.to.organisation=Adicionar \u00E0 organiza\u00E7\u00E3o
-rightsForm.guest=User type
-rightsForm.isLoginDenied=Login blocked
 rightsForm.roles=Fun\u00E7\u00F5es
 rightsForm.roles.for=Fun\u00E7\u00F5es para "{0}"
 rightsForm.sendLoginDeniedEmail=Notificar o usu\u00E1rio sobre acesso negado
-rightsForm.status=Status
 rightsForm.status.activ=Ativo
 rightsForm.status.any.visible=-
 rightsForm.status.deleted=Deletado
@@ -107,14 +77,7 @@ rightsForm.status.login_denied=Login bloqueado
 rightsForm.status.pending=Pendente
 rightsForm.status.permanent=N\u00E3o delet\u00E1vel
 rightsForm.title=Assign system roles and rights
-role.Admin=System administrator
-role.administrator=administrator
-role.author=Author
 role.curriculummanager=Gerente de curr\u00EDculo
-role.groupmanager=Group management
-role.guest=Anonymous guest
-role.guest.false=System user
-role.guest.true=Anonymous guest
 role.invitee=Convidado
 role.learnresourcemanager=Gestor de recurso did\u00E1tico
 role.lecturemanager=Gerente de Palestras
@@ -125,10 +88,6 @@ role.qualitymanager=Gerente de qualidade
 role.rolesmanager=Gestor de fun\u00E7\u00F5es
 role.sysadmin=Administrador do sistema
 role.user=Usu\u00E1rio
-role.usermanager=User management
-search.cancel=Action cancelled.
-search.form.afterDate=User created after
-search.form.beforeDate=User created before
 search.form.constraint.administrator=$\:role.administrator
 search.form.constraint.auth.LDAP=Senha LDAP
 search.form.constraint.auth.OAuth=Autentica\u00E7\u00E3o de rede social / Single Sign-On (OAuth)
@@ -137,10 +96,7 @@ search.form.constraint.auth.PerformX=PerformX
 search.form.constraint.auth.Shib=Shibboleth password 
 search.form.constraint.auth.ShibGeneric=$\:search.form.constraint.auth.Shib
 search.form.constraint.auth.WEBDAV=Senha WebDAV
-search.form.constraint.auth.none=No authentication
-search.form.constraint.author=Author
 search.form.constraint.curriculummanager=$\:role.curriculummanager
-search.form.constraint.groupmanager=Group manager
 search.form.constraint.guest=$\:role.guest
 search.form.constraint.invitee=$\:role.invitee
 search.form.constraint.learnresourcemanager=Gestor de recurso did\u00E1tico
@@ -153,7 +109,6 @@ search.form.constraint.qualitymanager=$\:role.qualitymanager
 search.form.constraint.rolesmanager=$\:role.rolesmanager
 search.form.constraint.sysadmin=$\:role.sysadmin
 search.form.constraint.user=$\:role.user
-search.form.constraint.usermanager=User manager
 search.form.id=ID
 search.form.login=Nome do usu\u00E1rio
 search.form.title.authentications=Authentication restrictions
@@ -167,13 +122,6 @@ search.form.userLoginBeforeDate=\u00DAltimo usu\u00E1rio logado antes
 select.organisation=Organiza\u00E7\u00E3o
 selectall=$org.olat.core.gui.components.table\:checkall
 sendtoken.wrong.auth=Este usu\u00E1rio possui tokens de autentica\u00E7\u00E3o que n\u00E3o podem ser alterados usando este link de senha. Examine e exclua esses tokens de autentica\u00E7\u00E3o adicionais primeiro.
-submit.cancel=Cancel
-submit.save=Save
-submit.search=Search
-table.auth.credential=Authorization
-table.auth.login=User name
-table.auth.provider=Provider
-table.header.action=Action
 table.header.vcard=Cart\u00E3o de visitas
 table.identity.action=A\u00E7\u00E3o
 table.identity.creationdate=Criado 
@@ -188,21 +136,8 @@ table.identity.status=Status
 table.identity.vcard=<i class\='o_icon o_icon-lg o_icon_home'> </i>
 table.name.firstName=Nome
 table.name.lastName=\u00DAltimo nome
-table.user.login=User name
 table.user.select=$org.olat.core.gui.components.table\:table.header.multiselect
 title.exeUAuths=Authentications
-title.exeUPrefs=System settings of {0}
-title.exeUProfile=User profile of {0}
-title.exeUProps=Properties of {0}
-title.exeUPwd=Change password for user {0}
-title.exeUQuota=Quota in personal folder
-title.mail=Send e-mail to list of users
-title.newuser=Create new user
-title.user.new=Create new OLAT user account
-title.user.search=Search for an OLAT user
-title.userlist=User list
-title.usersearch=User search
-user.found=User was found
 usermanagers=Gestor de usu\u00E1rios
 view.access=Reservas
 view.competences=Compet\u00EAncias
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_PT.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_PT.properties
index 3c8e6c41768c7375816ea29d9c7ad6e3e7c2f245..c5f751560ad2e740c41318d9fd3242843393123f 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_PT.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_pt_PT.properties
@@ -1,107 +1,31 @@
 #Fri Mar 23 15:02:47 CET 2018
-action.choose=Choose
 action.select=Selecionar
-authedit.delete.confirm=Are you sure you want to delete the authentication provider {0} for user {1}?
-authedit.delete.success=Authentication provider {0} deleted for user {1}.
 autocomplete.noresults=$org.olat.core.gui.control.generic.ajax.autocompletion\:autocomplete.noresults
 autocompletion.info=Pesquisa por login, primeiro nome, \u00FAltimo nome, e-mail ou matr\u00EDcula (n\u00FAmero de registro)
-changeuserpwd.cancel=Action was cancelled. Password remains unchanged.
-changeuserpwd.successful=New password saved successfully. It is valid from now on.
-command.mail=Send e-mail to these users
 content.usermgmt.text1=Aqui voc\u00EA pode modificar ou gerenciar dados de usu\u00E1rios existentes do OLAT. Favor iniciar sua busca de usu\u00E1rio.
 content.usermgmt.title=Gerenciamento do usu\u00E1rio
 content.usermgmt.userfound=Gerenciar configura\u00E7\u00F5es de usu\u00E1rio
 edit.uauth=Authentications
-edit.uprefs=System settings
-edit.uprofile=User profile
-edit.uprop=Properties
-edit.upwd=Change password
-edit.uquota=Quota
-edit.uroles=Roles
-error.no.user.found=No user was found with these attributes. Please try again.
-error.noaccess.to.user=You do not have enough rights to edit this user. Please contact {0}.
-error.password.nomatch=The two new passwords do not match.
-error.search.form.notempty=Please fill in at least one of the available fields.
-form.password.new1=New password
-form.password.new2=Confirm password
-form.please.enter.new=Please enter a new password for this user
-form.username=User name
-found.property=Property selected
 header.autocompletion=Busca combinada com auto-completar
 header.normal=Pesquisa com atributos de usu\u00E1rio
-mailto.userlist=List of users
-new.error.email.choosen=This e-mail address already exists. There is no need to create another account for this user. No data saved.
-new.error.loginname.choosen=This user name has already been allocated. Please try another one.
 new.error.loginname.empty=$org.olat.user\:form.checkUsername
-new.error.password.nomatch=The two passwords do not match.
-new.form.auth=OLAT password
-new.form.auth.false=Do not create now
-new.form.auth.true=Create now
-new.form.language=Language
-new.form.password.new1=Password
-new.form.password.new2=Verify password
-new.form.please.enter=Please enter information on new user 
-new.form.please.enter.pwd=Choose a password for new user
-new.form.username=User name
-new.user.cancel=Action cancelled. No new user account created.
-new.user.successful=The new user account has been created successfully.
-rightForm.error.anonymous.no.roles=Anonymous guests can not exercise system roles
-role.administrator=Administrator
-role.guest=Anonymous guest
-role.guest.false=System user
-role.guest.true=Anonymous guest
-role.author=Author
-role.groupmanager=Group management
-rightsForm.isLoginDenied=Login blocked
-role.usermanager=User management
-role.sysadmin=System administrator
-rightsForm.guest=User type
-rightsForm.status=Status
 rightsForm.status.activ=Ativo
 rightsForm.status.any.visible=-
 rightsForm.status.deleted=Deletado
 rightsForm.status.login_denied=Login bloqueado
 rightsForm.status.permanent=N\u00E3o delet\u00E1vel
 rightsForm.title=Assign system roles and rights
-search.cancel=Action cancelled.
-search.form.afterDate=User created after
-search.form.beforeDate=User created before
 search.form.constraint.administrator=$\:role.administrator
 search.form.constraint.auth.OLAT=OLAT/WebDAV password 
 search.form.constraint.auth.Shib=Shibboleth password 
-search.form.constraint.auth.none=No authentication
-search.form.constraint.author=Author
-search.form.constraint.groupmanager=Group manager
-search.form.constraint.logindenied=Account blocked
-search.form.constraint.usermanager=User manager
 search.form.login=Nome do usu\u00E1rio
 search.form.title.authentications=Authentication restrictions
 search.form.title.date=Creation date restrictions
 search.form.title.roles=System role restrictions
 search.form.title.user=Restri\u00E7\u00F5es de usu\u00E1rio
-submit.cancel=Cancel
-submit.save=Save
-submit.search=Search
 table.auth.credential=Authorization
-table.auth.login=User name
-table.auth.provider=Provider
-table.header.action=Action
 table.identity.action=A\u00E7\u00E3o
 table.identity.creationdate=Criado 
 table.identity.lastlogin=Ultimo Login 
 table.identity.name=Nome de usu\u00E1rio
 table.identity.vcard=<i class\='o_icon o_icon-lg o_icon_home'> </i>
-table.user.login=User name
-title.exeUAuths=Authentications
-title.exeUPrefs=System settings of {0}
-title.exeUProfile=User profile of {0}
-title.exeUProps=Properties of {0}
-title.exeUPwd=Change password for user {0}
-title.exeUQuota=Quota in personal folder
-title.mail=Send e-mail to list of users
-title.newuser=Create new user
-title.user.new=Create new OLAT user account
-title.user.search=Search for an OLAT user
-title.userlist=User list
-title.usersearch=User search
-user.found=User was found
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_ru.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_ru.properties
index c9b82dae73b93ed1afc5e4cc0ae978e8587553fa..2b236264c043f0088959ce8a7299eb2e726fafda 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_ru.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_ru.properties
@@ -24,7 +24,7 @@ error.password.nomatch=\u041E\u0431\u0430 \u043D\u043E\u0432\u044B\u0445 \u043F\
 error.search.form.notempty=\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u043A\u0430\u043A \u043C\u0438\u043D\u0438\u043C\u0443\u043C \u043E\u0434\u043D\u043E \u043F\u043E\u043B\u0435, \u043F\u043E\u0436\u0430\u0439\u043B\u0443\u0441\u0442\u0430.
 form.password.new1=\u041D\u043E\u0432\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C
 form.password.new2=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C
-form.please.enter.new=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043D\u043E\u0432\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C \u0434\u043B\u044F \u0434\u0430\u043D\u043D\u043E\u0433\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F, \u043F\u043E\u0436\u0430\u0439\u043B\u0443\u0441\u0442\u0430.
+form.please.enter.new=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043D\u043E\u0432\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C \u0434\u043B\u044F \u0434\u0430\u043D\u043D\u043E\u0433\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F, \u043F\u043E\u0436\u0430\u0439\u043B\u0443\u0441\u0442\u0430.{0}
 form.username=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
 found.property=\u0421\u0432\u043E\u0439\u0441\u0442\u0432\u043E \u0432\u044B\u0431\u0440\u0430\u043D\u043E
 header.autocompletion=\u041F\u043E\u0438\u0441\u043A \u0441 \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438\u043C \u0434\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435\u043C
@@ -41,7 +41,7 @@ new.form.language=\u042F\u0437\u044B\u043A
 new.form.password.new1=\u041F\u0430\u0440\u043E\u043B\u044C
 new.form.password.new2=\u0412\u0435\u0440\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C
 new.form.please.enter=\u0414\u0430\u043D\u043D\u044B\u0435 \u043E \u043B\u0438\u0447\u043D\u043E\u0441\u0442\u0438 \u043D\u043E\u0432\u043E\u0439 \u0443\u0447\u0451\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
-new.form.please.enter.pwd=\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u044C \u0434\u043B\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+new.form.please.enter.pwd=\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u044C \u0434\u043B\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.{0}
 new.form.username=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
 new.user.cancel=\u041E\u043F\u0435\u0440\u0430\u0446\u0438\u044F \u0431\u044B\u043B\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430. \u041D\u043E\u0432\u0430\u044F \u0443\u0447\u0451\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043D\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u0430.
 new.user.successful=\u0421\u043E\u0437\u0434\u0430\u043D\u0430 \u043D\u043E\u0432\u0430\u044F \u0443\u0447\u0451\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_sq.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_sq.properties
index d318b796efd241929f00bcb77ef474c8ac95179e..86cb19d7468204890ecdb2bddc478e095eac3aaa 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_sq.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_sq.properties
@@ -24,7 +24,7 @@ error.password.nomatch=Dy fjal\u00EBkalimet e reja nuk p\u00EBrputhen.
 error.search.form.notempty=Ju lutemi mbushni t\u00EB pakt\u00EBn nj\u00EB nga fushat e gatshme.
 form.password.new1=Fjal\u00EBkalimi i ri
 form.password.new2=Mirato fjal\u00EBkalimin
-form.please.enter.new=Ju lutemi shkruani fjal\u00EBkalimin e ri p\u00EBr k\u00EBt\u00EB shfryt\u00EBzues
+form.please.enter.new=Ju lutemi shkruani fjal\u00EBkalimin e ri p\u00EBr k\u00EBt\u00EB shfryt\u00EBzues.{0}
 form.username=Emri i shfryt\u00EBzuesit
 found.property=Tipar i p\u00EBrzgjedhur {0}
 header.autocompletion=K\u00EBrko me Autokompletim
@@ -43,7 +43,7 @@ new.form.mandatory=Kjo \u00EBsht\u00EB nj\u00EB fush\u00EB e detyrueshme, ju lut
 new.form.password.new1=Fjal\u00EBkalimi
 new.form.password.new2=V\u00EBrteto fjal\u00EBkalimin
 new.form.please.enter=Ju lutemi shkruani informata p\u00EBr shfryt\u00EBzuesin e ri 
-new.form.please.enter.pwd=P\u00EBrzgjedh nj\u00EB fjal\u00EBkalim p\u00EBr shfryt\u00EBzuesin e ri
+new.form.please.enter.pwd=P\u00EBrzgjedh nj\u00EB fjal\u00EBkalim p\u00EBr shfryt\u00EBzuesin e ri.{0}
 new.form.username=Emri i shfryt\u00EBzuesit 
 new.user.cancel=Aksioni u anulua. Nuk u krijua ndonj\u00EB llogari.
 new.user.successful=Llogaria e shfryt\u00EBzuesit t\u00EB ri u krijuar me sukses.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_zh_CN.properties
index 9024f4ebd2f11d74b53efb967da3b2fe2a346afe..f7619bb3e12923cde3e67d74134795ea2db05654 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_zh_CN.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_zh_CN.properties
@@ -36,7 +36,6 @@ error.search.form.notempty=\u8BF7\u81F3\u5C11\u586B\u5199\u4E00\u9879
 error.search.form.to.short=\u641C\u7D22\u5185\u5BB9\u8FC7\u77ED\uFF01
 form.password.new1=\u65B0\u5BC6\u7801
 form.password.new2=\u65B0\u5BC6\u7801\u786E\u8BA4
-form.please.enter.new=\u8BF7\u7ED9\u8BE5\u7528\u6237\u8BBE\u7F6E\u4E00\u4E2A\u65B0\u5BC6\u7801
 form.token.new.description=\u901A\u8FC7\u6309\u94AE"\u53D1\u9001\u5BC6\u7801\u94FE\u63A5"\u60A8\u53EF\u4EE5\u521B\u5EFA\u4E00\u4E2A\u5BC6\u7801\u94FE\u63A5\uFF0C\u5E76\u4F7F\u7528E-mail\u5C06\u6B64\u94FE\u63A5\u53D1\u9001\u7ED9\u7528\u6237\u3002\u5F53\u70B9\u51FB\u6B64\u94FE\u63A5\u65F6\uFF0C\u65E7\u5BC6\u7801\u4F1A\u66F4\u65B0\uFF0C\u540C\u65F6\u5141\u8BB8\u7528\u6237\u8F93\u5165\u65B0\u5BC6\u7801\u3002
 form.token.new.text=\u6D88\u606F
 form.token.new.title=\u53D1\u9001\u5BC6\u7801\u94FE\u63A5
@@ -59,7 +58,6 @@ new.form.mandatory=\u8FD9\u662F\u4EBA\u5DE5\u64CD\u4F5C\u90E8\u5206\uFF0C\u8BF7\
 new.form.password.new1=\u5BC6\u7801
 new.form.password.new2=\u68C0\u9A8C\u5BC6\u7801
 new.form.please.enter=\u8BF7\u8F93\u5165\u65B0\u7528\u6237\u4FE1\u606F
-new.form.please.enter.pwd=\u4E3A\u65B0\u7528\u6237\u9009\u62E9\u5BC6\u7801
 new.form.username=\u7528\u6237\u540D
 new.user.cancel=\u64CD\u4F5C\u53D6\u6D88\u3002\u672A\u521B\u5EFA\u7528\u6237\u3002
 new.user.successful=\u6210\u529F\u521B\u5EFA\u65B0\u7528\u6237
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_zh_TW.properties
index fdf41fc3e1e9f7166e79ed25616d80abbefd43f3..46e03b14bc3ea816acf805bcb49d0f5bb68c2bdc 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_zh_TW.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_zh_TW.properties
@@ -33,7 +33,6 @@ error.password.nomatch=\u9019\u5169\u500B\u65B0\u7684\u5BC6\u78BC\u4E0D\u4E00\u8
 error.search.form.notempty=\u8ACB\u81F3\u5C11\u586B\u5BEB\u4E00\u500B\u6B04\u4F4D\u3002
 form.password.new1=\u65B0\u7684\u5BC6\u78BC
 form.password.new2=\u78BA\u8A8D\u5BC6\u78BC
-form.please.enter.new=\u8ACB\u70BA\u9019\u500B\u4F7F\u7528\u8005\u8F38\u5165\u4E00\u500B\u65B0\u7684\u5BC6\u78BC
 form.token.new.description=\u85C9\u7531\u6309\u9215\u300C\u767C\u9001\u5BC6\u78BC\u9023\u7D50\u300D\u60A8\u53EF\u4EE5\u5EFA\u7ACB\u4E00\u500B\u5BC6\u78BC\u9023\u7D50\u4E26\u900F\u904E\u96FB\u5B50\u90F5\u4EF6\u50B3\u9001\u5B83\u7D66\u60A8\u7684\u4F7F\u7528\u8005\u3002\u7576\u9EDE\u64CA\u5B83\u6642\uFF0C\u820A\u7684\u5BC6\u78BC\u5C07\u88AB\u91CD\u8A2D\uFF0C\u5141\u8A31\u60A8\u7684\u4F7F\u7528\u8005\u8A2D\u5B9A\u4E00\u500B\u65B0\u7684\u5BC6\u78BC\u3002
 form.token.new.text=\u8A0A\u606F
 form.token.new.title=\u767C\u9001\u5BC6\u78BC\u9023\u7D50
@@ -56,7 +55,6 @@ new.form.mandatory=\u9019\u662F\u4E00\u500B\u5FC5\u586B\u6B04\u4F4D\uFF0C\u8ACB\
 new.form.password.new1=\u5BC6\u78BC
 new.form.password.new2=\u78BA\u8A8D\u5BC6\u78BC
 new.form.please.enter=\u8ACB\u8F38\u5165\u65B0\u4F7F\u7528\u8005\u7684\u8CC7\u8A0A
-new.form.please.enter.pwd=\u9078\u64C7\u4E00\u500B\u5BC6\u78BC\u7D66\u65B0\u4F7F\u7528\u8005
 new.form.username=\u4F7F\u7528\u8005\u540D\u7A31
 new.user.cancel=\u52D5\u4F5C\u53D6\u6D88\u3002\u6C92\u6709\u65B0\u7684\u4F7F\u7528\u8005\u5E33\u865F\u88AB\u5EFA\u7ACB\u3002
 new.user.successful=\u65B0\u7684\u4F7F\u7528\u8005\u5E33\u865F\u5DF2\u88AB\u6210\u529F\u5730\u5EFA\u7ACB\u4E86\u3002
diff --git a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java
index 4cef2ade28af33d0512b2e59f7203f921a1e0cef..3a8ffb6224f3ee8560229e48473e538de0044b11 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java
+++ b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java
@@ -19,6 +19,8 @@
  */
 package org.olat.admin.user.bulkChange;
 
+import static org.olat.login.ui.LoginUIFactory.formatDescriptionAsList;
+
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -26,6 +28,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 
+import org.apache.logging.log4j.Logger;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.VelocityEngine;
 import org.apache.velocity.context.Context;
@@ -42,7 +45,6 @@ import org.olat.core.id.Preferences;
 import org.olat.core.id.Roles;
 import org.olat.core.id.User;
 import org.olat.core.id.UserConstants;
-import org.apache.logging.log4j.Logger;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
@@ -54,6 +56,8 @@ import org.olat.core.util.mail.MailPackage;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.model.BusinessGroupMembershipChange;
 import org.olat.login.auth.OLATAuthManager;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.GenderPropertyHandler;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
@@ -106,13 +110,13 @@ public class UserBulkChangeManager implements InitializingBean {
 		}
 	}
 
-
 	public void changeSelectedIdentities(List<Identity> selIdentities, UserBulkChanges userBulkChanges,
 			List<String> notUpdatedIdentities, boolean isAdministrativeUser,
 			Translator trans, Identity actingIdentity, Roles actingRoles) {
 
 		Translator transWithFallback = userManager.getPropertyHandlerTranslator(trans);
 		String usageIdentifyer = UserBulkChangeStep00.class.getCanonicalName();
+		SyntaxValidator syntaxValidator = olatAuthManager.createPasswordSytaxValidator();
 
 		notUpdatedIdentities.clear();
 		List<Identity> changedIdentities = new ArrayList<>();
@@ -142,18 +146,21 @@ public class UserBulkChangeManager implements InitializingBean {
 
 			// change pwd
 			if (attributeChangeMap.containsKey(CRED_IDENTIFYER)) {
-				String newPwd = attributeChangeMap.get(CRED_IDENTIFYER);
-				if (StringHelper.containsNonWhitespace(newPwd)) {
-					if (!userManager.syntaxCheckOlatPassword(newPwd)) {
-						errorDesc = transWithFallback.translate("error.password");
+				String password = attributeChangeMap.get(CRED_IDENTIFYER);
+				if (StringHelper.containsNonWhitespace(password)) {
+					ValidationResult validationResult = syntaxValidator.validate(password, identity);
+					if (!validationResult.isValid()) {
+						String descriptions = formatDescriptionAsList(validationResult.getInvalidDescriptions(),
+								transWithFallback.getLocale());
+						errorDesc = transWithFallback.translate("error.password", new String[] { descriptions });
 						updateError = true;
 					}
 				} else {
-					newPwd = null;
+					password = null;
 				}
 				
 				if (canManagedCritical) {
-					olatAuthManager.changePasswordAsAdmin(identity, newPwd);
+					olatAuthManager.changePasswordAsAdmin(identity, password);
 				} else {
 					errorDesc = transWithFallback.translate("error.password");
 				}
diff --git a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep00.java b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep00.java
index 8b1cb770abffc78aa0bcc077b5921cffe02ee75c..4d66ab6a6a69287aed31694d342101855ef4528a 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep00.java
+++ b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep00.java
@@ -19,6 +19,8 @@
  */
 package org.olat.admin.user.bulkChange;
 
+import static org.olat.login.ui.LoginUIFactory.formatDescriptionAsList;
+
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -49,6 +51,9 @@ import org.olat.core.gui.control.generic.wizard.StepsRunContext;
 import org.olat.core.id.Identity;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.login.auth.OLATAuthManager;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
 import org.olat.user.ProfileFormController;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.GenericUnique127CharTextPropertyHandler;
@@ -96,6 +101,7 @@ class UserBulkChangeStep00 extends BasicStep {
 		private final List<MultipleSelectionElement> checkBoxes = new ArrayList<>();
 
 		private final boolean isAdministrativeUser;
+		private final SyntaxValidator syntaxValidator;
 		
 		@Autowired
 		private I18nManager i18nManager;
@@ -105,6 +111,8 @@ class UserBulkChangeStep00 extends BasicStep {
 		private UserBulkChangeManager ubcMan;
 		@Autowired
 		private BaseSecurityModule securityModule;
+		@Autowired
+		private OLATAuthManager olatAuthManager;
 		
 		public UserBulkChangeStepForm00(UserRequest ureq, WindowControl control, Form rootForm, StepsRunContext runContext) {
 			super(ureq, control, rootForm, runContext, LAYOUT_VERTICAL, null);
@@ -112,6 +120,7 @@ class UserBulkChangeStep00 extends BasicStep {
 			setTranslator(userManager.getPropertyHandlerTranslator(getTranslator()));
 			flc.setTranslator(getTranslator());
 			isAdministrativeUser = securityModule.isUserAllowedAdminProps(ureq.getUserSession().getRoles());
+			this.syntaxValidator = olatAuthManager.createPasswordSytaxValidator();
 
 			initForm(ureq);
 		}
@@ -187,8 +196,8 @@ class UserBulkChangeStep00 extends BasicStep {
 							if (handler.getName().equals(formItem.getName())) {
 								// first check on mandatoryness
 								if (userManager.isMandatoryUserProperty(usageIdentifyer, handler) && !StringHelper.containsNonWhitespace(evaluatedInputFieldValue)) {
-									formItem.setErrorKey("form.name." + handler.getName() + ".error.empty", null);				
-									return false;									
+									formItem.setErrorKey("form.name." + handler.getName() + ".error.empty", null);
+									return false;
 								}
 								// second check on property content
 								ValidationError valicationError = new ValidationError();
@@ -202,9 +211,15 @@ class UserBulkChangeStep00 extends BasicStep {
 						}
 
 						// special case: check password-syntax:
-						if (propertyField.getName().equals("password")&& !userManager.syntaxCheckOlatPassword(evaluatedInputFieldValue)) {
-							propertyField.setErrorKey("error.password", new String[] { evaluatedInputFieldValue });
-							return false;
+						if (propertyField.getName().equals("password")) {
+							String password = propertyField.getValue();
+							// No identity :-(
+							ValidationResult validationResult = syntaxValidator.validate(password);
+							if (!validationResult.isValid()) {
+								String descriptions = formatDescriptionAsList(validationResult.getInvalidDescriptions(), getLocale());
+								propertyField.setErrorKey("error.password", new String[] { descriptions });
+								return false;
+							}
 						}
 					}
 				}
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_ar.properties
index 66395c4201f8dc28edc73bd7f2d7b105283c0c57..41ec8b062e1d355cd76c2e24b74545713a923cd2 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_ar.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_ar.properties
@@ -3,7 +3,7 @@ bulk.auto.disc=\u0642\u0628\u0648\u0644 \u0634\u0631\u0648\u0637 \u0627\u0644\u0
 bulk.psw.newpsw=\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631
 bulk.psw.submit=\u062A\u0646\u0641\u064A\u0630
 bulk.psw.users=\u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=\u0627\u0644\u0644\u063A\u0629
 form.name.pwd=\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631
 main.menu.title=\u0643\u0644\u0645\u0629 \u0645\u0631\u0648\u0631 \u0623\u0648\u0644\u0627\u062A
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_bg.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_bg.properties
index 16af69d14b19fefebcd7336449eee1f06172905b..6ec4d8fe07c2edb5583f5597bb4280c5a5b5e63c 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_bg.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_bg.properties
@@ -1,5 +1,5 @@
 #Thu Jul 16 16:08:41 CEST 2009
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=\u0415\u0437\u0438\u043A
 form.name.pwd=\u041F\u0430\u0440\u043E\u043B\u0430
 role.add=\u041F\u0440\u0438\u0431\u0430\u0432\u0435\u0442\u0435
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_cs.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_cs.properties
index f8bb5fba7b2cf08bf5e095428c96917068f65593..dca50c4c2039a40ab94d76e4dd6b459b43278269 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_cs.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_cs.properties
@@ -1,5 +1,5 @@
 #Mon Mar 02 09:54:13 CET 2009
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=Jazyk
 form.name.pwd=Heslo
 role.add=Vlo\u017Eit
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties
index 5e5ebcac4c94ac6d43dfe6deed23344bdc1b1cc4..44325d35344aeb8c7396fc7ad717a2913595d780 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties
@@ -1,5 +1,5 @@
 #Mon Mar 02 09:54:04 CET 2009
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=Sprache
 form.name.pwd=Passwort
 role.add=hinzuf\u00FCgen
@@ -35,12 +35,12 @@ table.role.removed=Entfernte Rolle
 table.user.login=Benutzername
 title=\u00C4nderung von Benutzer-Attributen
 main.menu.title=OLAT Passwort 
-main.menu.title.alt=Massen\u00e4nderung des OLAT Passworts 
+main.menu.title.alt=Massen\u00E4nderung des OLAT Passworts 
 bulk.psw.users=Benutzerliste
 bulk.psw.newpsw=Passwort
-bulk.psw.submit=Ausf\u00fchren
+bulk.psw.submit=Ausf\u00FChren
 bulk.psw.done={0} Benutzer bearbeitet.
 bulk.auto.disc=Nutzungsbedingungen akzeptieren
 bulk.lang.german=Systemsprache auf Deutsch setzen
-step1a.description=Gruppe(n) ausw\u00e4hlen
-add.to.groups=Die Benutzer werden ausserdem folgenden Gruppen hinzugef\u00fcgt.
+step1a.description=Gruppe(n) ausw\u00E4hlen
+add.to.groups=Die Benutzer werden ausserdem folgenden Gruppen hinzugef\u00FCgt.
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_el.properties
index 1a26678a47f642f227822be475a549207c9c0431..1602aff0a2ebfa9f83bbe2b63cf95ab5862a4dbe 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_el.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_el.properties
@@ -5,7 +5,7 @@ bulk.psw.done=\u03A4\u03C1\u03BF\u03C0\u03BF\u03C0\u03BF\u03B9\u03AE\u03B8\u03B7
 bulk.psw.newpsw=\u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2
 bulk.psw.submit=\u03A5\u03C0\u03BF\u03B2\u03BF\u03BB\u03AE
 bulk.psw.users=\u039B\u03AF\u03C3\u03C4\u03B1 \u03C7\u03C1\u03B7\u03C3\u03C4\u03CE\u03BD
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=\u0393\u03BB\u03CE\u03C3\u03C3\u03B1
 form.name.pwd=\u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2
 main.menu.title=\u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 OLAT
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties
index dc03082029cd49fdb82900340eb65f2f1b3823cf..4100e7dd8d383a274fccdb2968aad12aa2a5c5bd 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties
@@ -5,7 +5,7 @@ bulk.psw.done={0} users edited.
 bulk.psw.newpsw=Password
 bulk.psw.submit=Submit
 bulk.psw.users=User list
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=Language
 form.name.pwd=Password
 main.menu.title=OLAT password
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_es.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_es.properties
index af85d417e6e3977c1723262399c1c8357b253221..5c95e36ede5c5703cca76141c97779f91be6a87b 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_es.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_es.properties
@@ -1,5 +1,5 @@
 #Mon Mar 09 05:14:49 CET 2009
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=Idioma
 form.name.pwd=Contrase\u00F1a
 role.add=Agregar
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_fr.properties
index 1a3238acc19a07ac4179e424d183ff30122246f2..d6ccdb9ea72a10f9c3b70bce5daa7fff3902b59f 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_fr.properties
@@ -6,7 +6,7 @@ bulk.psw.done={0} utilisateurs trait\u00E9s.
 bulk.psw.newpsw=Mot de passe
 bulk.psw.submit=Ex\u00E9cuter
 bulk.psw.users=Liste utilisateurs
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=langue
 form.name.pwd=mot de passe
 main.menu.title=Mot de passe OLAT
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_it.properties
index 27eee4bd11ccb49728103114e6bad7b2618e06b3..b00c9ec7f4dbee82242155d20ea88d31bf2e0d32 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_it.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_it.properties
@@ -6,7 +6,7 @@ bulk.psw.done={0} utenti elaborati.
 bulk.psw.newpsw=Password
 bulk.psw.submit=Eseguire
 bulk.psw.users=Lista utenti
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=Lingua
 form.name.pwd=Password
 main.menu.title=Password OLAT
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_jp.properties
index ec665a4deebb0a6ffa8ed6c2f4e1fc8d96d6e7d4..0df0c3442f1261fae365d7a611b9c7e380ee56ee 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_jp.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_jp.properties
@@ -5,7 +5,7 @@ bulk.psw.done={0} \u30E6\u30FC\u30B6\u304C\u7DE8\u96C6\u3055\u308C\u307E\u3057\u
 bulk.psw.newpsw=\u30D1\u30B9\u30EF\u30FC\u30C9
 bulk.psw.submit=\u9001\u4FE1
 bulk.psw.users=\u30E6\u30FC\u30B6\u30EA\u30B9\u30C8
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=\u8A00\u8A9E
 form.name.pwd=\u30D1\u30B9\u30EF\u30FC\u30C9
 main.menu.title=OLAT\u30D1\u30B9\u30EF\u30FC\u30C9
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_nl_NL.properties
index 9d8ce953c41a73afc0e201612b405adb0064f5a5..a57668277ec1b5612e255f71b78180f4f747d1dc 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_nl_NL.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_nl_NL.properties
@@ -5,7 +5,7 @@ bulk.psw.done={0} gebruikers aangepast.
 bulk.psw.newpsw=Wachtwoord
 bulk.psw.submit=Ingeven
 bulk.psw.users=Gebruikerslijst
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=Taal
 form.name.pwd=Wachtwoord
 main.menu.title=OLAT wachtwoord
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_pl.properties
index c7fa9aed3e7eb6c8bd6a604d43d63369f2220fc3..a5071983ce64f9fcaea73eb12f655403e8924515 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_pl.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_pl.properties
@@ -6,7 +6,7 @@ bulk.psw.done={0} edytowanych u\u017Cytkownik\u00F3w.
 bulk.psw.newpsw=Has\u0142o
 bulk.psw.submit=Zatwierd\u017A
 bulk.psw.users=Lista u\u017Cytkownik\u00F3w
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=J\u0119zyk
 form.name.pwd=Has\u0142o
 main.menu.title=Has\u0142o OLAT
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_pt_BR.properties
index e348d220ec43c00dedd80b2ff28007db133be535..369d45df1a5ef21f6e71c1d40676f6777d87fa57 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_pt_BR.properties
@@ -6,7 +6,7 @@ bulk.psw.done={0} usu\u00E1rios editados
 bulk.psw.newpsw=Senha
 bulk.psw.submit=Enviar
 bulk.psw.users=Lista de usu\u00E1rios
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=Idioma
 form.name.pwd=Senha
 main.menu.title=Senha OLAT
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_sq.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_sq.properties
index c95cd828b56264f1587bf838b819317c521a41d3..c647019789ca67c2fadacb258d3d44dabba7f032 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_sq.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_sq.properties
@@ -1,5 +1,5 @@
 #Mon Mar 02 09:54:11 CET 2009
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=Gjuha
 form.name.pwd=Fjal\u00EBkalimi
 role.add=shto
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_zh_CN.properties
index f773992ac941ef3b9e9a7afce786cc32937e7e8f..8a86736e1b476674b22149fc781bcd40b797e71c 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_zh_CN.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_zh_CN.properties
@@ -5,7 +5,7 @@ bulk.psw.done={0}\u7528\u6237\u7F16\u8F91\u8FC7\u3002
 bulk.psw.newpsw=\u5BC6\u7801
 bulk.psw.submit=\u63D0\u4EA4
 bulk.psw.users=\u7528\u6237\u5217\u8868
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=\u8BED\u8A00
 form.name.pwd=\u5BC6\u7801
 role.add=\u6DFB\u52A0
diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_zh_TW.properties
index aa56a1ca642a63e4944b0910f64fb618bff683b8..1f47a85f880796fffc1a84722ffea9602b3eadaa 100644
--- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_zh_TW.properties
+++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_zh_TW.properties
@@ -5,7 +5,7 @@ bulk.psw.done={0} \u500B\u4F7F\u7528\u8005\u88AB\u7DE8\u8F2F\u3002
 bulk.psw.newpsw=\u5BC6\u78BC
 bulk.psw.submit=\u9001\u51FA
 bulk.psw.users=\u4F7F\u7528\u8005\u6E05\u55AE
-error.password=$org.olat.user\:form.checkPassword
+error.password=$org.olat.user\:error.password.invalid
 form.name.language=\u8A9E\u8A00
 form.name.pwd=\u5BC6\u78BC
 main.menu.title=OLAT \u5BC6\u78BC
diff --git a/src/main/java/org/olat/admin/user/imp/ImportStep00.java b/src/main/java/org/olat/admin/user/imp/ImportStep00.java
index 9804f7f8e4b9a36cbce41e8159350d71e64a2afd..70075de371ffae86ec89595a38ed89237641f237 100644
--- a/src/main/java/org/olat/admin/user/imp/ImportStep00.java
+++ b/src/main/java/org/olat/admin/user/imp/ImportStep00.java
@@ -24,10 +24,13 @@
 */
 package org.olat.admin.user.imp;
 
+import static org.olat.login.ui.LoginUIFactory.formatDescriptionAsList;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import javax.servlet.http.HttpServletRequest;
 
@@ -56,6 +59,9 @@ import org.olat.core.id.User;
 import org.olat.core.id.UserConstants;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.i18n.I18nModule;
+import org.olat.login.auth.OLATAuthManager;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
 import org.olat.shibboleth.ShibbolethDispatcher;
 import org.olat.shibboleth.ShibbolethModule;
 import org.olat.user.UserManager;
@@ -104,6 +110,9 @@ class ImportStep00 extends BasicStep {
 		private List<UpdateIdentity> updateIdents;
 		private List<TransientIdentity> newIdents;
 		private List<UserPropertyHandler> userPropertyHandlers;
+		
+		private final SyntaxValidator passwordSyntaxValidator;
+		private final SyntaxValidator usernameSyntaxValidator;
 
 		@Autowired
 		private UserManager um;
@@ -112,6 +121,8 @@ class ImportStep00 extends BasicStep {
 		@Autowired
 		private I18nModule i18nModule;
 		@Autowired
+		private OLATAuthManager olatAuthManager;
+		@Autowired
 		private BaseSecurity securityManager;
 		@Autowired
 		private ShibbolethModule shibbolethModule;
@@ -119,6 +130,8 @@ class ImportStep00 extends BasicStep {
 		public ImportStepForm00(UserRequest ureq, WindowControl control, Form rootForm, StepsRunContext runContext) {
 			super(ureq, control, rootForm, runContext, LAYOUT_VERTICAL, null);
 			flc.setTranslator(getTranslator());
+			this.usernameSyntaxValidator = olatAuthManager.createUsernameSytaxValidator();
+			this.passwordSyntaxValidator = olatAuthManager.createPasswordSytaxValidator();
 			initForm(ureq);
 		}
 
@@ -192,11 +205,6 @@ class ImportStep00 extends BasicStep {
 				// login row
 				if (parts.length > columnId) {
 					login = parts[columnId].trim();
-					if (!UserManager.getInstance().syntaxCheckOlatLogin(login)) {
-						textAreaElement.setErrorKey("error.login", new String[] { String.valueOf(i + 1), login });
-						importDataError = true;
-						break;
-					}
 				} else {
 					textAreaElement.setErrorKey("error.columncount", new String[] { String.valueOf(i + 1) });
 					importDataError = true;
@@ -205,39 +213,33 @@ class ImportStep00 extends BasicStep {
 				columnId++;
 
 				// pwd row
+				pwd = null;
 				if (canCreateOLATPassword) {
 					if (parts.length > columnId) {
-						pwd = parts[columnId].trim();
-						if (StringHelper.containsNonWhitespace(pwd)) {
-							if(pwd.startsWith(UserImportController.SHIBBOLETH_MARKER) && shibbolethModule.isEnableShibbolethLogins()) {
-								String authusername = pwd.substring(UserImportController.SHIBBOLETH_MARKER.length());
-								Authentication auth = securityManager.findAuthenticationByAuthusername(authusername, ShibbolethDispatcher.PROVIDER_SHIB);
-								if(auth != null) {
-									String authLogin = auth.getIdentity().getName();
-									if(!login.equals(authLogin)) {
-										textAreaElement.setErrorKey("error.shibbolet.name.inuse", new String[] { String.valueOf(i + 1), authusername });
-										importDataError = true;
-										break;
-									}
-								}
-							} else if (!UserManager.getInstance().syntaxCheckOlatPassword(pwd)) {
-								textAreaElement.setErrorKey("error.pwd", new String[] { String.valueOf(i + 1), pwd });
-								importDataError = true;
-								break;
-							}
-						} else {
-							// treat all white-space-only passwords as non-passwords.
-							// the user generation code below will then generate no
-							// authentication token for this user
-							pwd = null;
+						String trimmedPwd = parts[columnId].trim();
+						// treat all white-space-only passwords as non-passwords.
+						// the user generation code below will then generate no
+						// authentication token for this user.
+						if (StringHelper.containsNonWhitespace(trimmedPwd)) {
+							pwd = trimmedPwd;
 						}
 					} else {
 						textAreaElement.setErrorKey("error.columncount", new String[] { String.valueOf(i + 1) });
 						importDataError = true;
 						break;
 					}
-				} else {
-					pwd = null;
+				}
+				if(pwd != null && pwd.startsWith(UserImportController.SHIBBOLETH_MARKER) && shibbolethModule.isEnableShibbolethLogins()) {
+					String authusername = pwd.substring(UserImportController.SHIBBOLETH_MARKER.length());
+					Authentication auth = securityManager.findAuthenticationByAuthusername(authusername, ShibbolethDispatcher.PROVIDER_SHIB);
+					if(auth != null) {
+						String authLogin = auth.getIdentity().getName();
+						if(!login.equals(authLogin)) {
+							textAreaElement.setErrorKey("error.shibbolet.name.inuse", new String[] { String.valueOf(i + 1), authusername });
+							importDataError = true;
+							break;
+						}
+					}
 				}
 				columnId++;
 
@@ -261,11 +263,14 @@ class ImportStep00 extends BasicStep {
 					// update existing accounts, add info message
 					
 					UpdateIdentity uIdentity = new UpdateIdentity(ident, pwd, lang);
-					idents.add(uIdentity);
-					updateIdents.add(uIdentity);
-
+					
 					importDataError = updateUserProperties(uIdentity, ident.getUser(), parts, i, columnId, importedEmails);
 					if(importDataError) break;
+					importDataError = !validatePassword(pwd, uIdentity, i);
+					if(importDataError) break;
+
+					idents.add(uIdentity);
+					updateIdents.add(uIdentity);
 				} else {
 					// no identity/user yet, create
 					// check that no user with same login name is already in list
@@ -278,16 +283,21 @@ class ImportStep00 extends BasicStep {
 						}
 					}
 
-					TransientIdentity ud = new TransientIdentity();
+					TransientIdentity uIdentity = new TransientIdentity();
 					// insert fix fields: login, pwd, lang from above
-					ud.setName(login);
-					ud.setPassword(pwd);
-					ud.setLanguage(lang);
-					importDataError = updateUserProperties(ud, null, parts, i, columnId, importedEmails);
+					uIdentity.setName(login);
+					uIdentity.setPassword(pwd);
+					uIdentity.setLanguage(lang);
+					
+					importDataError = updateUserProperties(uIdentity, null, parts, i, columnId, importedEmails);
+					if(importDataError) break;
+					importDataError = !validateUsername(login, uIdentity, i);
+					if(importDataError) break;
+					importDataError = !validatePassword(pwd, uIdentity, i);
 					if(importDataError) break;
 					
-					idents.add(ud);
-					newIdents.add(ud);
+					idents.add(uIdentity);
+					newIdents.add(uIdentity);
 				}
 			}
 
@@ -367,6 +377,30 @@ class ImportStep00 extends BasicStep {
 			}
 			return importDataError;
 		}
+		
+		private boolean validatePassword(String password, Identity userIdentity, int column) {
+			if (StringHelper.containsNonWhitespace(password)) {
+				ValidationResult validationResult = passwordSyntaxValidator.validate(password, userIdentity);
+				if (!validationResult.isValid()) {
+					String descriptions = formatDescriptionAsList(validationResult.getInvalidDescriptions(), getLocale());
+					textAreaElement.setErrorKey("error.pwd", new String[] { String.valueOf(column + 1), descriptions });
+					return false;
+				}
+			}
+			return true;
+		}
+		
+		private boolean validateUsername(String username, Identity userIdentity, int column) {
+			if (StringHelper.containsNonWhitespace(username)) {
+				ValidationResult validationResult = usernameSyntaxValidator.validate(username, userIdentity);
+				if (!validationResult.isValid()) {
+					String descriptions = validationResult.getInvalidDescriptions().get(0).getText(getLocale());
+					textAreaElement.setErrorKey("error.login", new String[] { String.valueOf(column + 1), descriptions });
+					return false;
+				}
+			}
+			return true;
+		}
 
 		@Override
 		protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
@@ -395,7 +429,13 @@ class ImportStep00 extends BasicStep {
 				mandatoryProperties += ", " + translate(userPropertyHandler.i18nColumnDescriptorLabelKey()) + mandatoryChar;
 			}
 			textContainer.contextPut("mandatoryProperties", mandatoryProperties);
-
+			
+			List<String> passwordRules = passwordSyntaxValidator.getAllDescriptions().stream()
+					.map(d -> d.getText(getLocale()))
+					.collect(Collectors.toList());
+			textContainer.contextPut("passwordRules", passwordRules);
+			textContainer.contextPut("passwordIntro", translate("form.password.validation.rules", new String[] { }));
+			
 			textAreaElement = uifactory.addTextAreaElement("importform", "form.importdata", -1, 10, 100, false, false, "", formLayout);
 			textAreaElement.setMandatory(true);
 			textAreaElement.setNotEmptyCheck("error.emptyform");
diff --git a/src/main/java/org/olat/admin/user/imp/_content/step0.html b/src/main/java/org/olat/admin/user/imp/_content/step0.html
index 04c5c96c58ca1ec76f3a57fb5b29b62bb0a2b583..332605d272947743ac9eb7fc1fa61f59d34378a5 100644
--- a/src/main/java/org/olat/admin/user/imp/_content/step0.html
+++ b/src/main/java/org/olat/admin/user/imp/_content/step0.html
@@ -9,10 +9,15 @@ $r.translate("formatexplanation.part2a")
 $r.translate("formatexplanation.part3")
 <p />	
 
-$r.translate("formatexplanation.conventions")
+<p>
+$r.translateWithPackage("org.olat.user", "form.checkUsername")
+</p>
+
+$r.translate("form.pwd.intro")
 <ul>
-	<li>$r.translateWithPackage("org.olat.user", "form.checkPassword")</li>
-	<li>$r.translateWithPackage("org.olat.user", "form.checkUsername")</li>
+#foreach($passwordRule in $passwordRules)
+	<li>$passwordRule</li>
+#end
 </ul>
 
 #o_togglebox_start("o_usermanagement_importexample" "$r.translate('import.example')")
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_ar.properties
index 55fac65a4f6f2da37d5d5edf391ed898b34eadc2..d3eb13ce449a8308fd583762249c818c95f74aa4 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_ar.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_ar.properties
@@ -7,10 +7,8 @@ error.emptyform=\u064A\u0631\u062C\u0649 \u0627\u0644\u0643\u062A\u0627\u0628\u0
 error.lang=\u062E\u0637\u0623 \u0641\u0649 \u0627\u0644\u062E\u0637 {0}\: \u0627\u0644\u0644\u063A\u0629 "{1}" \u063A\u064A\u0631 \u0635\u062D\u064A\u062D\u060C \u064A\u0631\u062D\u0649 \u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0631\u0645\u0648\u0632 \u0644\u063A\u0629 \u0635\u062D\u064A\u062D\u0629.
 error.length=\u062E\u0637\u0623 \u0641\u0649 \u0627\u0644\u062E\u0637 {0}\: \u0642\u064A\u0645\u0629 \u0627\u0644\u0635\u0641\u0629 "{1}" \u0628\u0647\u0627 \u0623\u0643\u062B\u0631 \u0645\u0646 127 \u062D\u0631\u0641\u0627\u064B.
 error.lengthorformat={2} \:{1} \u062E\u0637\u0623 \u0641\u0649 \u0627\u0644\u062E\u0637 {0}\: \u0641\u0649 \u0627\u0644\u0639\u0645\u0648\u062F
-error.login=\u062E\u0637\u0623 \u0641\u0649 \u0627\u0644\u062E\u0637 {0}\: \u0627\u0633\u0645 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645 "{1}" \u0644\u0627 \u064A\u062A\u0641\u0642 \u0645\u0639 \u0623\u0648\u0644\u0627\u062A\u060C \u064A\u0631\u062C\u0649 \u062A\u063A\u064A\u064A\u0631 \u0627\u0633\u0645 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645.
 error.login.douplicate=\u062E\u0637\u0623 \u0641\u0649 \u0627\u0644\u062E\u0637 {0}\: \u0627\u0633\u0645 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645 "{1}" \u064A\u0648\u062C\u062F \u0645\u0631\u062A\u064A\u0646 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0648\u062C\u0648\u062F \u0645\u0631\u0629 \u0648\u0627\u062D\u062F\u0629 \u0641\u0642\u0637.
 error.mandatory=\u062E\u0637\u0623 \u0641\u0649 \u0627\u0644\u062E\u0637 {0}\: \u0627\u0644\u0635\u0641\u0629 "{1}" \u0636\u0631\u0648\u0631\u064A\u0629.
-error.pwd=\u062E\u0637\u0623 \u0641\u0649 \u0627\u0644\u062E\u0637 {0}\: \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 "{1}" \u0644\u0627 \u062A\u062A\u0641\u0642 \u0645\u0639 \u0623\u0648\u0644\u0627\u062A\u060C \u064A\u0631\u062C\u0649 \u062A\u063A\u064A\u064A\u0631 \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631.
 form.importdata=\u0646\u0633\u062E \u0627\u0644\u0635\u0641\u0648\u0641 \u0645\u0646 \u0627\u0643\u0633\u0644
 formatexplanation.part1=<ul><br>. \u0627\u0633\u062A\u062E\u062F\u0645 \u0627\u0644\u0627\u0643\u0633\u0644 (\u0623\u0648 \u0627\u0644\u0623\u0648\u0641\u0633 \u0627\u0644\u0645\u0641\u062A\u0648\u062D) \u0637\u0628\u0642\u0627 \u0644\u0644\u0635\u0648\u0631\u0629 \u0628\u0627\u0644\u0623\u0633\u0641\u0644\u060C \u0648\u0627\u0646\u0642\u0631 \u0639\u0644\u0649 \u0627\u0644\u0645\u062B\u0627\u0644
 formatexplanation.part2.cancreatepassword=\u060C {0} \u0627\u0633\u0645 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645\u060C \u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631\u060C \u0627\u0644\u0644\u063A\u0629 \r\n</li> \u0639\u0646\u062F \u062A\u0631\u0643 \u062E\u0627\u0646\u0629 "\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631" \u0641\u0627\u0631\u063A\u0629 \u0641\u0625\u0646\u0647 \u064A\u062C\u0628 \u062A\u0632\u0648\u064A\u062F \u0647\u0630\u0627 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645 \u0628\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0644\u0627\u062D\u0642\u0627\u064B</li><li>
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_bg.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_bg.properties
index 2e25df3b601b44f85aa0321ee504979b0f060c8b..27cacd8e20aa0a49d7b181389f5dadb4f06f9bbd 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_bg.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_bg.properties
@@ -7,10 +7,9 @@ error.emptyform=\u041C\u043E\u043B\u044F, \u043F\u043E\u043F\u044A\u043B\u043D\u
 error.lang=\u0413\u0440\u0435\u0448\u043A\u0430 \u043D\u0430 \u0440\u0435\u0434 {0}\: \u0435\u0437\u0438\u043A\u044A\u0442 "{1}" \u0435 \u043D\u0435\u0432\u0430\u043B\u0438\u0434\u0435\u043D. \u041C\u043E\u043B\u044F, \u0438\u0437\u043F\u043E\u043B\u0437\u0432\u0430\u0439\u0442\u0435 \u0432\u0430\u043B\u0438\u0434\u0435\u043D \u0435\u0437\u0438\u043A\u043E\u0432 \u043A\u043E\u0434.
 error.length=\u0413\u0440\u0435\u0448\u043A\u0430 \u043D\u0430 \u0440\u0435\u0434 {0}\: \u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0442\u0430 \u043D\u0430 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 "{1}" \u0438\u043C\u0430 \u043F\u043E\u0432\u0435\u0447\u0435 \u043E\u0442 127 \u0437\u043D\u0430\u043A\u0430.
 error.lengthorformat=\u0413\u0440\u0435\u0448\u043A\u0430 \u043D\u0430 \u0440\u0435\u0434 {0} \u0432 \u043A\u043E\u043B\u043E\u043D\u0430 {1}\: {2}
-error.login=\u0413\u0440\u0435\u0448\u043A\u0430 \u043D\u0430 \u0440\u0435\u0434 {0}\: \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E\u0442\u043E \u0438\u043C\u0435 "{1}" \u043D\u0435 \u0441\u044A\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0430 \u043D\u0430 \u0443\u0441\u043B\u043E\u0432\u0438\u044F\u0442\u0430 \u043D\u0430 \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u0442\u0430. \u041C\u043E\u043B\u044F, \u043F\u0440\u043E\u043C\u0435\u043D\u0435\u0442\u0435 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E\u0442\u043E \u0438\u043C\u0435.
+error.login=\u0413\u0440\u0435\u0448\u043A\u0430 \u043D\u0430 \u0440\u0435\u0434 {0}\: {1}
 error.login.douplicate=\u0413\u0440\u0435\u0448\u043A\u0430 \u043D\u0430 \u0440\u0435\u0434 {0}\: \u041F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E\u0442\u043E \u0438\u043C\u0435 "{1}" \u0435 \u043D\u0430\u043C\u0435\u0440\u0435\u043D\u043E \u043F\u043E\u043D\u0435 \u0434\u0432\u0430 \u043F\u044A\u0442\u0438, \u043D\u043E \u0442\u043E \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0443\u043D\u0438\u043A\u0430\u043B\u043D\u043E.
 error.mandatory=\u0413\u0440\u0435\u0448\u043A\u0430 \u043D\u0430 \u0440\u0435\u0434 {0}\: \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044A\u0442 "{1}" \u0435 \u0437\u0430\u0434\u044A\u043B\u0436\u0438\u0442\u0435\u043B\u0435\u043D.
-error.pwd=\u0413\u0440\u0435\u0448\u043A\u0430 \u043D\u0430 \u0440\u0435\u0434 {0}\: \u043F\u0430\u0440\u043E\u043B\u0430\u0442\u0430 "{1}" \u043D\u0435 \u043E\u0442\u0433\u043E\u0432\u0430\u0440\u044F \u043D\u0430 \u0443\u0441\u043B\u043E\u0432\u0438\u044F\u0442\u0430 \u043D\u0430 \u0441\u0438\u0441\u0442\u0435\u043C\u0430\u0442\u0430. \u041C\u043E\u043B\u044F, \u043F\u0440\u043E\u043C\u0435\u043D\u0435\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u0430\u0442\u0430.
 form.importdata=\u041A\u043E\u043F\u0438\u0440\u0430\u043D\u0438 \u0440\u0435\u0434\u043E\u0432\u0435 \u043E\u0442 Excel
 formatexplanation.part1=\u0418\u0437\u043F\u043E\u043B\u0437\u0432\u0430\u0439\u0442\u0435 Excel (\u0438\u043B\u0438 OpenOffice) \u0441\u043F\u043E\u0440\u0435\u0434 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435\u0442\u043E \u043F\u043E-\u0434\u043E\u043B\u0443 (\u043A\u043B\u0438\u043A\u043D\u0435\u0442\u0435 \u043D\u0430 \u043F\u0440\u0438\u043C\u0435\u0440).<br><ul>
 formatexplanation.part2.cancreatepassword=\u041F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E \u0438\u043C\u0435, \u043F\u0430\u0440\u043E\u043B\u0430, \u0435\u0437\u0438\u043A{0}. </li><li>\u0410\u043A\u043E \u043F\u043E\u043B\u0435\u0442\u043E "\u041F\u0430\u0440\u043E\u043B\u0430" \u043E\u0441\u0442\u0430\u043D\u0435 \u043F\u0440\u0430\u0437\u043D\u043E, \u0432\u0438\u0435 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u043E\u0441\u0438\u0433\u0443\u0440\u0438\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u0430 \u0437\u0430 \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u044F \u043F\u043E-\u043A\u044A\u0441\u043D\u043E.</li> 
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_cs.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_cs.properties
index 8153aa7dcea905c6b73248acc8307962163aa1b7..da0a4a8331b6f7def8a7e8ff0a86f7a518dc5f63 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_cs.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_cs.properties
@@ -7,10 +7,9 @@ error.emptyform=Dopl\u0148te pros\u00EDm toto pole.
 error.lang=Chyba na \u0159\u00E1dce {0}\: jazyk "{1}" je \u0161patn\u011B. Vlo\u017Ete spr\u00E1v\u00FD k\u00F3d jazyka.
 error.length=Chyba na \u0159\u00E1dku {0}\: hodnota atributu "{1}" m\u00E1 v\u00EDce ne\u017E 127 znak\u016F.
 error.lengthorformat=Chyba na \u0159\u00E1dku {0} ve sloupci {1}\: {2}
-error.login=Chyba na \u0159\u00E1dce {0}\: u\u017Eivatelsk\u00E9 jm\u00E9no "{1}" neodpov\u00EDd\u00E1 konvenc\u00EDm OLATu. Zm\u011B\u0148te ho pros\u00EDm.
+error.login=Chyba na \u0159\u00E1dce {0}\: {1}
 error.login.douplicate=Chyba na \u0159\u00E1dku {0}\: U\u017Eivatelsk\u00E9 jm\u00E9no "{1}" bylo nalezeno alespo\u0148 dvakr\u00E1t, ale m\u00E1 b\u00FDt unik\u00E1tn\u00ED.
 error.mandatory=Chyba na \u0159\u00E1dku {0}\: atribut "{1}" je povinn\u00FD.
-error.pwd=Chyba na \u0159\u00E1dce {0}\: heslo "{1}" neodpov\u00EDd\u00E1 konvenc\u00EDm OLATu. Zm\u011B\u0148te ho pros\u00EDm.
 form.importdata=\u0158\u00E1dky zkop\u00EDrovan\u00E9 z Excelu
 formatexplanation.part1=Pou\u017Eijte Excel (nebo OpenOffice) podle n\u00E1sleduj\u00EDc\u00EDho obr\u00E1zku (klikn\u011Bte pro uk\u00E1zku).<br><ul>
 formatexplanation.part2.cancreatepassword=U\u017Eivatelsk\u00E9 jm\u00E9no, heslo, jazyk{0}. </li><li>Pokud z\u016Fstane pole "Heslo" pr\u00E1zdn\u00E9 budete muset p\u0159i\u0159adit u\u017Eivateli heslo pozd\u011Bji.</li> 
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_da.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_da.properties
index 4ad99b36c9fa1e077790f6108ba5eddecca85c83..dc201dc83487d3c83fe7fb10987740a36ebe38b9 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_da.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_da.properties
@@ -3,8 +3,7 @@ error.columncount=Fejl i linie {0}\: ikke nok elementer
 error.email=Fejl i linie {0}\: e-mailadresse "{1}" er ugyldig. Angiv venligst en komplet og gyldig e-mailadresse.
 error.email.douplicate=Fejl i linie {0}\: e-mailadressen "{1}" er allerede i brug for bruger "{2}". 
 error.lang=Fejl i linie {0}\: sproget  "{1}" er ugyldigt. Brug venligst en gyldig sprogkode.
-error.login=Fejl i linie {0}\: brugernavnet "{1}" overholder ikke OLAT reglerne. Tilpas venligst brugernavnet.
-error.pwd=Fejl i linie {0}\: kodeordet "{1}" overholder ikke OLAT reglerne. Udskift venligst kodeordet.
+error.login=Fejl i linie {0}\: {1}
 form.importdata=Kopierede kolonner fra Excel
 import.confirm={0} brugere i tabellen, {1} nye, og {2} eksisterende. <br>Vil du importere de {1} nye brugere til OLAT?
 import.example=Eksempel billede
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_de.properties
index 0c82089701280942fd21eeda80ef795e8fd40af4..bdf5e909a77d081373375ae76b9e7da6b82372bf 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_de.properties
@@ -8,18 +8,18 @@ error.emptyform=Bitte f\u00FCllen Sie dieses Feld aus.
 error.lang=Fehler auf Zeile {0}\: die Sprache "{1}" ist ung\u00FCltig. Bitte geben Sie eine g\u00FCltige Sprache an.
 error.length=Fehler auf Zeile {0}\: der Wert "{1}" hat mehr als 127 Zeichen.
 error.lengthorformat=Fehler auf Zeile {0} in Spalte {1}\: {2}
-error.login=Fehler auf Zeile {0}\: der Benutzername "{1}" entspricht nicht den OLAT-Konventionen. Bitte \u00E4ndern Sie diesen Benutzernamen.
+error.login=Fehler auf Zeile {0}\: {1}
 error.login.douplicate=Fehler auf Zeile {0}\: Der Benutzername "{1}" ist mehrfach in der Liste vorhanden, sollte jedoch einmalig sein.
 error.mandatory=Fehler auf Zeile {0}\: die Angabe von "{1}" ist obligatorisch.
-error.pwd=Fehler auf Zeile {0}\: das Passwort "{1}" entspricht nicht den OLAT-Konventionen. Bitte \u00E4ndern Sie dieses Passwort.
+error.pwd=Fehler auf Zeile {0}\: Das Password ist nicht g\u00FCltig.{1}
 error.shibbolet.name.inuse=Fehler auf Zeile {0}\: dieser Shibboleth-Identifikator "{1}" wird bereits in einem bestehenden Konto benutzt.
 form.importdata=Kopierte Zeilen aus Excel
+form.pwd.intro=Das neue Password muss folgende Kriterien erf\u00FCllen:
 formatexplanation.part1=Benutzen Sie Excel (oder OpenOffice) gem\u00E4ss untenstehender Abbildung (Auf Beispielabbildung klicken).<br><ul>
 formatexplanation.part2.cancreatepassword=Benutzername *, Passwort, Sprache{0}.</li><li>Wenn das Feld "Passwort" leer gelassen wird, m\u00FCssen Sie dem Benutzer sp\u00E4ter ein Passwort setzen.</li>
 formatexplanation.part2.cannotcreatepassword=Benutzername *, Sprache{0}. </li>
 formatexplanation.part2a=<li>Folgende Felder sind auszuf\u00FCllen (solche mit * zwingend)\:
 formatexplanation.part3=<li>Wenn das Feld "Sprache" leer gelassen wird, so wird die Standardsprache der OLAT-Installation verwendet.</li><li>Orientieren Sie sich in der Excel-Vorlage \u00FCber die Reihenfolge der Angaben und \u00FCber weitere konfigurationsabh\u00E4ngige Spalten. </li></ul>
-formatexplanation.conventions=Richtlinien f\u00fcr Benutzername und Passwort:
 import.confirm=Sie m\u00F6chten {0} Benutzer importieren. Davon ist/sind {1} neu, {2} ist/sind bereits in OLAT vorhanden. Klicken Sie auf "Fertigstellen", um {1} neue Benutzer zu importieren.
 import.description0=Gef\u00FChrt von einem Wizard k\u00F6nnen Sie mehrere Benutzer auf einmal importieren. Sie ben\u00F6tigen dazu eine Liste mit durch Tabulator separierten Werten.
 import.description1=Was Sie w\u00E4hrend des Wizards erwartet\: 
@@ -27,7 +27,7 @@ import.description2=<i>Datenbeispiele\:</i> Sie sehen in einer Beispielabbildung
 import.description3=<i>Dateneingabe\:</i> Sie kopieren die Zeilen aus der Excel-Datei
 import.description4=<i>Vorschau der Benutzerdaten\:</i> Sie sehen, welche Benutzer bereits im System sind und welche neu angelegt werden.
 import.example=Beispielabbildung
-import.errors=Die Benutzer wurden teilweise angelegt. Es gab Fehler w\u00e4hrend den Import Prozess: {0}
+import.errors=Die Benutzer wurden teilweise angelegt. Es gab Fehler w\u00E4hrend den Import Prozess: {0}
 import.start=Benutzerimport starten
 import.success=Die neuen Benutzer wurden erfolgreich angelegt.
 import.user.existing.alt=Dieser Benutzer existiert bereits, er wird nicht neu angelegt
@@ -40,7 +40,7 @@ step1.description=Vorschau der Benutzerdaten
 step1.nonewusers=Die Tabelle enth\u00E4lt keine neuen Benutzer. Sie k\u00F6nnen keine Benutzer importieren.
 step1.passwordEmails=Achtung: bei Passwort\u00E4nderungen f\u00FCr existierende Benutzer wird unabh\u00E4ngig von ihren Einstellungen eine E-Mail-Benachrichtigung verschickt.
 step1.short.descr=Vorschau
-step2.description=Gruppe(n) ausw\u00e4hlen
+step2.description=Gruppe(n) ausw\u00E4hlen
 step3.description=E-Mail-Benachrichtigung
 step3.short.description=E-Mail-Benachrichtigung
 step3.send.label=
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_el.properties
index 0998df4ee9693135dad441dab38649e3d5817bac..9f82bca1a47226e2da30d571eaf7e1e7dc834042 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_el.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_el.properties
@@ -8,10 +8,9 @@ error.emptyform=\u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03C3\u03C5\u0
 error.lang=\u039B\u03AC\u03B8\u03BF\u03C2 \u03C3\u03C4\u03B7 \u03B3\u03C1\u03B1\u03BC\u03BC\u03AE {0}\: \u03B7 \u03B3\u03BB\u03CE\u03C3\u03C3\u03B1 "{1}" \u03B4\u03B5\u03BD \u03B5\u03AF\u03BD\u03B1\u03B9 \u03AD\u03B3\u03BA\u03C5\u03C1\u03B7. \u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03BF\u03CD\u03BC\u03B5 \u03C7\u03C1\u03B7\u03C3\u03B9\u03BC\u03BF\u03C0\u03BF\u03B9\u03AE\u03C3\u03C4\u03B5 \u03AD\u03BD\u03B1\u03BD \u03AD\u03B3\u03BA\u03C5\u03C1\u03BF \u03BA\u03CE\u03B4\u03B9\u03BA\u03B1 \u03B3\u03BB\u03CE\u03C3\u03C3\u03B1\u03C2.
 error.length=\u039B\u03AC\u03B8\u03BF\u03C2 \u03C3\u03C4\u03B7 \u03B3\u03C1\u03B1\u03BC\u03BC\u03AE {0}\: \u03B7 \u03C4\u03B9\u03BC\u03AE \u03C4\u03BF\u03C5 \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03B7\u03C1\u03B9\u03C3\u03C4\u03B9\u03BA\u03BF\u03CD "{1}" \u03C0\u03B5\u03C1\u03B9\u03AD\u03C7\u03B5\u03B9 \u03C0\u03AC\u03BD\u03C9 \u03B1\u03C0\u03BF 127 \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1\u03B5\u03C2.
 error.lengthorformat=\u039B\u03AC\u03B8\u03BF\u03C2 \u03C3\u03C4\u03B7 \u03B3\u03C1\u03B1\u03BC\u03BC\u03AE {0} \u03C4\u03B7\u03C2 \u03C3\u03C4\u03AE\u03BB\u03B7\u03C2 {1}\: {2}
-error.login=\u039B\u03AC\u03B8\u03BF\u03C2 \u03C3\u03C4\u03B7 \u03B3\u03C1\u03B1\u03BC\u03BC\u03AE {0}\: \u03C4\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 "{1}" \u03B4\u03B5\u03BD \u03B1\u03BA\u03BF\u03BB\u03BF\u03C5\u03B8\u03B5\u03AF \u03C4\u03BF\u03C5\u03C2 \u03BA\u03B1\u03BD\u03CC\u03BD\u03B5\u03C2 \u03BF\u03BD\u03BF\u03BC\u03B1\u03C4\u03BF\u03BB\u03BF\u03B3\u03AF\u03B1\u03C2. \u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03B1\u03BB\u03BB\u03AC\u03BE\u03C4\u03B5 \u03C4\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7.
+error.login=\u039B\u03AC\u03B8\u03BF\u03C2 \u03C3\u03C4\u03B7 \u03B3\u03C1\u03B1\u03BC\u03BC\u03AE {0}\: {1}
 error.login.douplicate=\u039B\u03AC\u03B8\u03BF\u03C2 \u03C3\u03C4\u03B7 \u03B3\u03C1\u03B1\u03BC\u03BC\u03AE {0}\: \u03A4\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 "{1}" \u03AD\u03C7\u03B5\u03B9 \u03B2\u03C1\u03B5\u03B8\u03B5\u03AF \u03B4\u03B9\u03C2 \u03B1\u03BB\u03BB\u03AC \u03C0\u03C1\u03AD\u03C0\u03B5\u03B9 \u03BD\u03B1 \u03B5\u03AF\u03BD\u03B1\u03B9 \u03BC\u03BF\u03BD\u03B1\u03B4\u03B9\u03BA\u03CC.
 error.mandatory=\u039B\u03AC\u03B8\u03BF\u03C2 \u03C3\u03C4\u03B7 \u03B3\u03C1\u03B1\u03BC\u03BC\u03AE {0}\: \u03C4\u03BF \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03B7\u03C1\u03B9\u03C4\u03B9\u03BA\u03CC "{1}" \u03B5\u03AF\u03BD\u03B1\u03B9 \u03C5\u03C0\u03BF\u03C7\u03C1\u03B5\u03C9\u03C4\u03B9\u03BA\u03CC.
-error.pwd=\u039B\u03AC\u03B8\u03BF\u03C2 \u03C3\u03C4\u03B7 \u03B3\u03C1\u03B1\u03BC\u03BC\u03AE {0}\: \u03BF \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 "{1}" \u03B4\u03B5\u03BD \u03B1\u03BA\u03BF\u03BB\u03BF\u03C5\u03B8\u03B5\u03AF \u03C4\u03BF\u03C5\u03C2 \u03BA\u03B1\u03BD\u03CC\u03BD\u03B5\u03C2 \u03BF\u03BD\u03BF\u03BC\u03B1\u03C4\u03BF\u03BB\u03BF\u03B3\u03AF\u03B1\u03C2. \u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03BF\u03CD\u03BC\u03B5 \u03B1\u03BB\u03BB\u03AC\u03BE\u03C4\u03B5 \u03C4\u03BF\u03BD \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2.
 form.importdata=\u0391\u03BD\u03C4\u03B9\u03B3\u03C1\u03B1\u03BC\u03BC\u03AD\u03BD\u03B5\u03C2 \u03C3\u03B5\u03B9\u03C1\u03AD\u03C2 \u03B1\u03C0\u03CC \u03C4\u03BF Excel
 formatexplanation.part1=\u03A7\u03C1\u03B7\u03C3\u03B9\u03BC\u03BF\u03C0\u03BF\u03B9\u03AE\u03C3\u03C4\u03B5 \u03C4\u03BF Excel (\u03AE \u03C4\u03BF OpenOffice) \u03CC\u03C0\u03C9\u03C2 \u03C0\u03B5\u03C1\u03B9\u03B3\u03C1\u03AC\u03C6\u03B5\u03C4\u03B1\u03B9 \u03C3\u03C4\u03B7\u03BD \u03C0\u03B1\u03C1\u03B1\u03BA\u03AC\u03C4\u03C9 \u03B5\u03B9\u03BA\u03CC\u03BD\u03B1 (\u03BA\u03AC\u03BD\u03C4\u03B5 \u03BA\u03BB\u03B9\u03BA \u03C3\u03C4\u03BF \u03C0\u03B1\u03C1\u03AC\u03B4\u03B5\u03B9\u03B3\u03BC\u03B1).<br><ul>
 formatexplanation.part2.cancreatepassword=<\u038C\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7, \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2, \u03B3\u03BB\u03CE\u03C3\u03C3\u03B1{0}. </li><li>\u0386\u03BD \u03C4\u03BF \u03C0\u03B5\u03B4\u03AF\u03BF "\u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2" \u03C0\u03B1\u03C1\u03B1\u03BC\u03B5\u03AF\u03BD\u03B5\u03B9 \u03BA\u03B5\u03BD\u03CC, \u03C4\u03CC\u03C4\u03B5 \u03B8\u03B1 \u03C0\u03C1\u03AD\u03C0\u03B5\u03B9 \u03B1\u03C1\u03B3\u03CC\u03C4\u03B5\u03C1\u03B1 \u03BD\u03B1 \u03BF\u03C1\u03AF\u03C3\u03B5\u03C4\u03B5 \u03B5\u03BD\u03B1\u03BD \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03B3\u03B9\u03B1 \u03C4\u03BF \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03B5\u03BA\u03B5\u03AF\u03BD\u03BF\u03BD.</li>
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_en.properties
index f6835fb70fcd4cadcfb6ae79d5883bd59c013da7..4db4ab026abadf5c9394c4ddfd044009b67b7d0d 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_en.properties
@@ -8,13 +8,13 @@ error.emptyform=Please fill in this field.
 error.lang=Error in line {0}\: the language "{1}" is invalid. Please use a valid language code.
 error.length=Error in line {0}\: the attribute value "{1}" has more than 127 characters.
 error.lengthorformat=Error in line {0} in column {1}\: {2}
-error.login=Error in line {0}\: the user name "{1}" does not follow OLAT conventions. Please change that user name.
+error.login=Error in line {0}\: {1}
 error.login.douplicate=Error in line {0}\: The user name "{1}" has been found at least twice but needs to be unique.
 error.mandatory=Error in line {0}\: the attribute "{1}" is mandatory.
-error.pwd=Error in line {0}\: the password "{1}" does not follow OLAT conventions. Please change this password.
+error.pwd=Error in line {0}\: the password is not valid.{1}
 error.shibbolet.name.inuse=Error in line {0}\: this shibboleth identifier "{1}" is already in use in an existing account.
 form.importdata=Copied rows from Excel
-formatexplanation.conventions=Rules for username and password\:
+form.pwd.intro=The new password must meet the following criteria:
 formatexplanation.part1=Use Excel (or OpenOffice) according to the image below (click on example).<br><ul>
 formatexplanation.part2.cancreatepassword=User name *, password, language{0}. </li><li>If the field "Password" remains empty you will have to provide that user with a password later on.</li>
 formatexplanation.part2.cannotcreatepassword=User name *, language{0}. </li>
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_es.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_es.properties
index 8f4ec4c5b89ee2bac2484c653265fadd6368c469..310094cb24012f6811adeec03e9b18c81fbf8c05 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_es.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_es.properties
@@ -7,10 +7,9 @@ error.emptyform=Por favor, complete este campo.
 error.lang=Error en la l\u00EDnea {0}\: el idioma "{1}" no es v\u00E1lido. Por favor utiliza un c\u00F3digo de idioma v\u00E1lido.
 error.length=Error en la l\u00EDnea {0}\: el valor del atributo "{1}" tiene m\u00E1s de 127 caracteres.
 error.lengthorformat=Error en la l\u00EDnea {0} en columna {1}\: {2}
-error.login=Error en la l\u00EDnea {0}\: el nombre de usuario "{1}" no cumple las convenciones de OLAT. Por favor cambia el nombre de usuario.
+error.login=Error en la l\u00EDnea {0}\: {1}
 error.login.douplicate=Error en la l\u00EDnea {0}\: el nombre de usuario "{1}" se ha encontrado por lo menos dos veces, pero debe ser \u00FAnico.
 error.mandatory=Error en la l\u00EDnea {0}\: el atributo "{1}" es obligatorio.
-error.pwd=Error en la l\u00EDnea {0}\: la contrase\u00F1a "{1}" no cumple las convenciones de OLAT. Por favor cambia la contrase\u00F1a.
 form.importdata=Filas copiadas de Excel
 formatexplanation.part1=Usar Excel (o OpenOffice), como mostrado en la siguiente imagen (click en el ejemplo).<br><ul>
 formatexplanation.part2.cancreatepassword=Nombre de usuario, contrase\u00F1a, idioma{0}. </li><li>Si el campo "Contrase\u00F1a" permanece vac\u00EDo tendr\u00E1 que poner una contrase\u00F1a m\u00E1s adelante.</li>
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_fa.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_fa.properties
index a8078d6287038d963d164adefb0ad72ca2eba2b6..e7348ed34113110b72ddb362ced2edbe60631c78 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_fa.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_fa.properties
@@ -1,13 +1,4 @@
 #Mon Mar 02 09:54:12 CET 2009
-error.columncount=Error in line {0}\: not enough elements
-error.email=Error in line {0}\: the e-mail "{1}" is invalid. Please indicate a complete and valid e-mail address.
-error.email.douplicate=Error in line {0}\: the e-mail "{1}" is already used by user "{2}". 
-error.lang=Error in line {0}\: the language "{1}" is invalid. Please use a valid language code.
-error.login=Error in line {0}\: the user name "{1}" does not follow OLAT conventions. Please change that user name.
-error.pwd=Error in line {0}\: the password "{1}" does not follow OLAT conventions. Please change this password.
-form.importdata=Copied columns from Excel
-import.confirm={0} users in the table, {1} new, and {2} existing. <br>Do you want to import the new {1} users into OLAT?
-import.example=Example image
 import.success=\u06A9\u0627\u0631\u0628\u0631 \u062C\u062F\u06CC\u062F \u0628\u0627 \u0645\u0648\u0641\u0642\u06CC\u062A \u0627\u06CC\u062C\u0627\u062F \u0634\u062F.
 step3.send.label=
 submit.import=\u0630\u062E\u06CC\u0631\u0647
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_fr.properties
index 309f2470636bdad18da76d5426a271c3afd4efe5..7b3aa1af682edbc406fa1d1b44908fa7ac5c4f34 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_fr.properties
@@ -8,13 +8,11 @@ error.emptyform=Le formulaire ne peut pas \u00EAtre vide.
 error.lang=Erreur \u00E0 la ligne {0}\: la langue "{1}" n'est pas valable. Veuillez indiquer une langue admise.
 error.length=Erreur \u00E0 la ligne {0}\: la valeur "{1}" contient plus que 127 signes.
 error.lengthorformat=Erreur \u00E0 la ligne {0} dans la colonne {1}\: {2}
-error.login=Erreur \u00E0 la ligne {0}\: le nom d'utilisateur "{1}" ne corrrespond pas aux conventions d'OLAT. Veuillez modifier ce nom d'utilisateur.
+error.login=Erreur \u00E0 la ligne {0}\: {1}
 error.login.douplicate=Erreur \u00E0 la ligne  {0}\: le nom d'utilisateur "{1}" est contenu plusieurs fois dans la liste, il doit cependant \u00EAtre unique.
 error.mandatory=Erreur \u00E0 la ligne  {0}\: l'indication de "{1}" est obligatoire.
-error.pwd=Erreur \u00E0 la ligne {0}\: le mot de passe "{1}" ne corrrespond pas aux conventions d'OLAT. Veuillez modifier ce mot de passe.
 error.shibbolet.name.inuse=Erreur ligne {0}\: l'identifiant Shibbolet "{1}" est d\u00E9j\u00E0 utilis\u00E9 par un compte existant.
 form.importdata=Colonnes copi\u00E9es d'Excel
-formatexplanation.conventions=R\u00E8gles pour le nom d'utilisateur et le mot de passe\:
 formatexplanation.part1=Utilisez Excel (ou OpenOffice), conform\u00E9ment \u00E0 l'illustration ci-dessous. (Cliquez sur la reproduction d'exemple).<br><ul>
 formatexplanation.part2.cancreatepassword=<li>Les colonnes suivantes sont obligatoires\: Login, mot de passe, langue.</li><li>La colonne avec le mot de passe peut \u00EAtre vide.</li>
 formatexplanation.part2.cannotcreatepassword=<li>Les colonnes suivantes sont obligatoires\: Login, mot de passe. </li>
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_it.properties
index eb0df1bb8d77ccf6a5b5d59c1c5208c6738c5c40..18de23f2fe042ec5f75681a3fc41447cf14bfd6d 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_it.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_it.properties
@@ -8,13 +8,11 @@ error.emptyform=Completi questo formulario, p.f.
 error.lang=Errore alla righa {0}\: la lingua "{1}" non \u00E8 valida. Inserisca una lingua valida, p.f.
 error.length=Errore alla righa {0}\: il valore "{1}" ha pi\u00F9 di 127 segni.
 error.lengthorformat=Errore alla righa {0} nella colonna {1}\: {2}
-error.login=Errore alla righa {0}\: il nome d'utente "{1}" non \u00E8 adeguato alle convenzioni OLAT. Lo modifichi, p.f.
+error.login=Errore alla righa {0}\: {1}
 error.login.douplicate=Errore alla righa {0}\: il nome d'utente "{1}" \u00E8 gi\u00E0 presente pi\u00F9 volte nella lista, dovrebbe per\u00F2 esserci solo una volta.
 error.mandatory=Errore alla righa {0}\: indicare "{1}" \u00E8 obbligatorio.
-error.pwd=Errore alla righa {0}\: la password "{1}" non \u00E8 adeguata alle convenzioni OLAT. La modifichi, p.f.
 error.shibbolet.name.inuse=Errore nella linea {0}\: questo identificatore shibboleth "{1}" \u00E8 gi\u00E0 in uso in un account esistente.
 form.importdata=Righe copiate da Excel
-formatexplanation.conventions=Regole per nome utente e password\:
 formatexplanation.part1=Utilizzi Excel (oppure OpenOffice) conformemente all'illustrazione sottostante (cliccare sull'immagine).<br><ul>
 formatexplanation.part2.cancreatepassword=Nome d'utente *, password, lingua{0}.</li><li>La casella della password pu\u00F2 restare vuota\: in tal caso dovr\u00E0 dare una password all'utente in un secondo tempo</li>
 formatexplanation.part2.cannotcreatepassword=\: Nome d'utente *, lingua{0}. </li>
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_jp.properties
index 3eb8fde7168fcf74aff92fd7dd0be07871d137ce..d4ae30504fc0c8a901c2f1b69331e7884fe2617b 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_jp.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_jp.properties
@@ -7,10 +7,9 @@ error.emptyform=\u3053\u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u306E\u5165\u529B\u30
 error.lang={0} \u884C\u76EE\u306B\u30A8\u30E9\u30FC\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\: \u8A00\u8A9E "{1}" \u304C\u6709\u52B9\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u6709\u52B9\u306A\u8A00\u8A9E\u30B3\u30FC\u30C9\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002
 error.length={0} \u884C\u76EE\u306B\u30A8\u30E9\u30FC\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\: \u5C5E\u6027\u5024 "{1}" \u306B127\u6587\u5B57\u4EE5\u4E0A\u542B\u307E\u308C\u3066\u3044\u307E\u3059\u3002
 error.lengthorformat={1} \u30AB\u30E9\u30E0\u5185\u306E {0} \u884C\u76EE\u306B\u30A8\u30E9\u30FC\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\: {2}
-error.login={0} \u884C\u76EE\u306B\u30A8\u30E9\u30FC\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\: \u30E6\u30FC\u30B6\u540D "{1}" \u306F\u3001OLAT\u306E\u30EB\u30FC\u30EB\u306B\u5F93\u3063\u3066\u3057\u307E\u305B\u3093\u3002\u30E6\u30FC\u30B6\u540D\u3092\u5909\u66F4\u3057\u3066\u304F\u3060\u3055\u3044\u3002
+error.login={0} \u884C\u76EE\u306B\u30A8\u30E9\u30FC\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\: {1}
 error.login.douplicate={0} \u884C\u76EE\u306B\u30A8\u30E9\u30FC\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\: \u30E6\u30FC\u30B6\u540D "{1}" \u304C2\u56DE\u4EE5\u4E0A\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3002\u30E6\u30FC\u30B6\u540D\u306F\u3001\u30E6\u30CB\u30FC\u30AF (\u56FA\u6709) \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002
 error.mandatory={0} \u884C\u76EE\u306B\u30A8\u30E9\u30FC\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\: \u5C5E\u6027 "{1}" \u306F\u3001\u5FC5\u9808\u9805\u76EE\u3067\u3059\u3002
-error.pwd={0} \u884C\u76EE\u306B\u30A8\u30E9\u30FC\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\: \u30D1\u30B9\u30EF\u30FC\u30C9 "{1}" \u306F\u3001OLAT\u306E\u30EB\u30FC\u30EB\u306B\u5F93\u3063\u3066\u3057\u307E\u305B\u3093\u3002\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u5909\u66F4\u3057\u3066\u304F\u3060\u3055\u3044\u3002
 form.importdata=Excel\u304B\u3089\u30B3\u30D4\u30FC\u3055\u308C\u305F\u884C
 formatexplanation.part1=\u4EE5\u4E0B\u306E\u30A4\u30E1\u30FC\u30B8\u306B\u5F93\u3063\u3066\u3001Excel (\u307E\u305F\u306FOpenOffice)\u3092\u4F7F\u7528\u3057\u307E\u3059 (\u30B5\u30F3\u30D7\u30EB\u3092\u30AF\u30EA\u30C3\u30AF)\u3002<br /><ul>
 formatexplanation.part2.cannotcreatepassword=\u30E6\u30FC\u30B6\u540D\u3001\u8A00\u8A9E\u3000{0}</li>
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_lt.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_lt.properties
index 7357fc3e36e30c4902fb8d50ffc3e653b6e92989..f26b7291fa226343f4a040ac61126959f656e829 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_lt.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_lt.properties
@@ -3,8 +3,7 @@ error.columncount=Klaida eilut\u0117je {0}\: nepakankamas kiekis element\u0173
 error.email=Klaida eilut\u0117je {0}\: el. pa\u0161tas "{1}" neteisingas. Pra\u0161ome nurodyti piln\u0105 ir galiojant\u012F el. pa\u0161to adres\u0105.
 error.email.douplicate=Klaida eilut\u0117je {0}\: el. pa\u0161tas adresas "{1}" jau yra naudojamas vartotojo "{2}".
 error.lang=Klaida eilut\u0117je {0}\: kalba "{1}" yra neteisinga. Pra\u0161ome naudoti galiojant\u012F kalbos kod\u0105.
-error.login=Klaida eilut\u0117je {0}\: naudotojo vardas "{1}" ne\u012Feina \u012F OLAT konvencijas. Pra\u0161ome pasikeisti vartotojo vard\u0105.
-error.pwd=Klaida eilut\u0117je {0}\: slapta\u017Eodis "{1}" ne\u012Feina \u012F OLAT konvencijas. Pra\u0161ome pasikeisti slapta\u017Eod\u012F.
+error.login=Klaida eilut\u0117je {0}\: {1}
 form.importdata=Nukopijuoti stulpeliai i\u0161 Excel
 import.confirm={0}vartotojai lentel\u0117je,{1} naujas,  ir {2}egzistuojantis. <br>Ar norite \u012Fvesti naujus {1} vartotojus \u012F OLAT?
 import.example=Pavyzdinis vaizdas
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_nl_NL.properties
index a210a923e02d946de82bfd369df5da44baa9ce3c..4d34c6a534901c7a8f41c065e829b74ea9c78bb9 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_nl_NL.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_nl_NL.properties
@@ -8,10 +8,9 @@ error.emptyform=Gelieve dit veld in te vullen.
 error.lang=Fout in lijn {0}\: de taal "{1}" is ongeldig. Gelieve een geldige taalcode te gebruiken.
 error.length=Fout in lijn {0}\: De attributenwaarde "{1}"  bevat meer dan 127 tekens.
 error.lengthorformat=Fout in lijn {0} in kolum {1}\: {2}
-error.login=Fout in lijn {0}\: De gebruikersnaam "{1}" voldoet niet aan de OLAT conventies. Gelieve die gebruikersnaam te veranderen.
+error.login=Fout in lijn {0}\: {1}
 error.login.douplicate=Fout in lijn {0}\: De gebruikersnaam "{1}" werd tenminste twee keer gevonden maar moet uniek zijn.
 error.mandatory=Fout in lijn {0}\: Het attribuut "{1}" is verplicht.
-error.pwd=Fout in lijn {0}\: Het wachtwoord "{1}" voldoet niet aan de OLAT conventies. Gelieve dit wachtwoord te veranderen.
 form.importdata=Gekopieerde rijen uit Excel
 formatexplanation.part1=Gebruik Excel (of OpenOffice) volgens de onderstaande afbeelding (klik op voorbeeld).<br><ul>
 formatexplanation.part2.cancreatepassword=Gebruikersnaam *, wachtwoord, taal{0}. </li><li>Als het veld "Wachtwoord" leeg blijft, moet u die gebruiker later voorzien van een wachtwoord.</li>
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pl.properties
index a6896d838d3dfa27d763848f25ae185924a5145b..4204bc25d2659af6b6a294a0a7f66b71708f82e7 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pl.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pl.properties
@@ -8,12 +8,10 @@ error.emptyform=Ten formularz nie mo\u017Ce by\u0107 pusty.
 error.lang=B\u0142\u0105d w linii {0}\: j\u0119zyk "{1}" nie jest warto\u015Bci\u0105 poprawn\u0105. U\u017Cyj poprawnego kodu j\u0119zyka, np. pl
 error.length=B\u0142\u0105d w linii {0}\: warto\u015Bc atrybutu "{1}" ma wi\u0119cej niz 127 znak\u00F3w.
 error.lengthorformat=B\u0142\u0105d w linii {0} w kolumnie {1}\: {2}
-error.login=B\u0142\u0105d w linii {0}\: nazwa u\u017Cytkownika  "{1}" nie jest zgodna z konwencj\u0105 OLAT.
+error.login=B\u0142\u0105d w linii {0}\: {1}
 error.login.douplicate=B\u0142\u0105d w linii {0}\: nazwa u\u017Cytkownika "{1}" zosta\u0142a dwukrotnie odnaleziona, a musi byc niepowtarzalna.
 error.mandatory=B\u0142\u0105d w linii {0}\: atrybut "{1}" jest obowi\u0105zkowy.
-error.pwd=B\u0142\u0105d w linii {0}\: has\u0142o "{1}" nie jest zgodna z konwencj\u0105 OLAT.
 form.importdata=Kolumny skopiowane z Excel-a
-formatexplanation.conventions=Zasady dla nazwy u\u017Cytkownika i has\u0142a\:
 formatexplanation.part1=U\u017Cyj Excel-a (lub OpenOffice-a) tak jak pokazano na poni\u017Cszym rysunku. <br><ul>
 formatexplanation.part2.cancreatepassword=<li>Te pola s\u0105 obowi\u0105zkowe\: nazwa u\u017Cytkownika, has\u0142o, j\u0119zyk. Kolumna "has\u0142o" mo\u017Ce by\u0107 pusta. 
 formatexplanation.part2.cannotcreatepassword=<li>Te pola s\u0105 obowi\u0105zkowe\: login, j\u0119zyk.
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pt_BR.properties
index 05024e496a00f6930a4db82100ee22091dc319ce..a373217b830c488d7873089cf40f7d18070c9f6e 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pt_BR.properties
@@ -8,13 +8,11 @@ error.emptyform=Favor complete esse campo.
 error.lang=Erro na linha {0}\: o idioma "{1}" \u00E9 inv\u00E1lido. Favor usar um c\u00F3digo de linguagem v\u00E1lido.
 error.length=Erro na linha {0}\: o valor atribu\u00EDdo "{1}" tem mais que 127 caract\u00E9res.
 error.lengthorformat=Erro na linha {0} na coluna {1}\: {2}
-error.login=Erro na linha {0}\: o nome de usu\u00E1rio "{1}" n\u00E3o segue as conven\u00E7\u00F5es do OLAT. Favor mudar este nome de usu\u00E1rio.
+error.login=Erro na linha {0}\: {1}
 error.login.douplicate=Erro na linha {0}\: O usu\u00E1rio "{1}" foi encontrado pelo menos duas vezes mas precisa ser \u00FAnico.
 error.mandatory=Erro na linha {0}\: a informa\u00E7\u00E3o "{1}" \u00E9 obrigat\u00F3rio.
-error.pwd=Erro na linha {0}\: a senha "{1}" n\u00E3o segue as conven\u00E7\u00F5es do OLAT. Favor mudar esta senha.
 error.shibbolet.name.inuse=Erro na linha {0}\: este identificador shibboleth "{1}" j\u00E1 est\u00E1 em uso em uma conta existente.
 form.importdata=Colunas copiadas do Excel
-formatexplanation.conventions=Regras para nome de usu\u00E1rio e senha\:
 formatexplanation.part1=Use o Excel (ou OpenOffice) de acordo com a imagem abaixo (clique no exemplo).<br><ul>
 formatexplanation.part2.cancreatepassword=Usu\u00E1rio, senha, idioma{0}. </li><li>Se o campo "senha" permanecer vazio voc\u00EA ir\u00E1 precisar fornecer a aquele usu\u00E1rio uma senha posteriormente.</li> 
 formatexplanation.part2.cannotcreatepassword=User name, language{0}. </li>
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pt_PT.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pt_PT.properties
index f930c6b0300b436ef6b9b6aff6caed507f8bafe4..7fa9f66ac1a9f33d99bad68f26e11cf583e36159 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pt_PT.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_pt_PT.properties
@@ -3,8 +3,7 @@ error.columncount=Erro na linha {0}\: elementos n\u00E3o suficientes
 error.email=Erro na linha {0}\: o e-mail "{1}" \u00E9 inv\u00E1lido. Favor indicar um endere\u00E7o de e-mail completo e v\u00E1lido.
 error.email.douplicate=Erro na linha {0}\: o e-mail "{1}" j\u00E1 \u00E9 usado pelo usu\u00E1rio "{2}". 
 error.lang=Erro na linha {0}\: o idioma "{1}" \u00E9 inv\u00E1lido. Favor usar um c\u00F3digo de linguagem v\u00E1lido.
-error.login=Erro na linha {0}\: o nome de usu\u00E1rio "{1}" n\u00E3o segue as conven\u00E7\u00F5es do OLAT. Favor mudar este nome de usu\u00E1rio.
-error.pwd=Erro na linha {0}\: a senha "{1}" n\u00E3o segue as conven\u00E7\u00F5es do OLAT. Favor mudar esta senha.
+error.login=Erro na linha {0}\: {1}
 form.importdata=Colunas copiadas do Excel
 import.confirm={0} usu\u00E1rios na tabela , {1} novo, e {2} existente. <br>Voc\u00EA quer importar os novos {1} usu\u00E1rios do OLAT?
 import.example=Imagem exemplo
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_ru.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_ru.properties
index 79d0e95a646eebe769e3fbc57fabbd2cdb56d958..9c9aac938b6e137eafc5c40f3b2f777e34ac863a 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_ru.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_ru.properties
@@ -3,8 +3,7 @@ error.columncount=\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u0441\u0442\u0440
 error.email=\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u0441\u0442\u0440\u043E\u043A\u0435 {0}\: email "{1}" \u043D\u0435\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u0435\u043D. \u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043F\u043E\u043B\u043D\u044B\u0439 \u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 e-mail \u0430\u0434\u0440\u0435\u0441, \u043F\u043E\u0436\u0430\u0439\u043B\u0443\u0441\u0442\u0430.
 error.email.douplicate=\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u0441\u0442\u0440\u043E\u043A\u0435 {0}\: e-mail "{1}" \u0443\u0436\u0435 \u043F\u0440\u0438\u043D\u0430\u0434\u043B\u0435\u0436\u0438\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E "{2}".
 error.lang=\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u0441\u0442\u0440\u043E\u043A\u0435 {0}\: \u044F\u0437\u044B\u043A  "{1}" \u043D\u0435\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u0435\u043D. \u0417\u0430\u0434\u0430\u0439\u0442\u0435 \u0438\u043C\u0435\u044E\u0449\u0438\u0439\u0441\u044F \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0435 \u044F\u0437\u044B\u043A.
-error.login=\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u0441\u0442\u0440\u043E\u043A\u0435 {0}\: \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F "{1}" \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430\u043C \u0441\u0438\u0441\u0442\u0435\u043C\u044B OLAT. \u0418\u0437\u043C\u0435\u043D\u0438\u0442\u0435 \u0434\u0430\u043D\u043D\u043E\u0435 \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F, \u043F\u043E\u0436\u0430\u0439\u043B\u0443\u0441\u0442\u0430.
-error.pwd=\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u0441\u0442\u0440\u043E\u043A\u0435 {0}\: \u043F\u0430\u0440\u043E\u043B\u044C "{1}" \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430\u043C \u0441\u0438\u0441\u0442\u0435\u043C\u044B OLAT. \u0418\u0437\u043C\u0435\u043D\u0438\u0442\u0435 \u0434\u0430\u043D\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C, \u043F\u043E\u0436\u0430\u0439\u043B\u0443\u0441\u0442\u0430.
+error.login=\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u0441\u0442\u0440\u043E\u043A\u0435 {0}\: {1}
 form.importdata=\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0435 \u0441\u0442\u043E\u043B\u0431\u0446\u044B \u0438\u0437 Excel
 import.confirm={0} \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0432 \u0442\u0430\u0431\u043B\u0438\u0446\u0435, \u0438\u0437 \u043A\u043E\u0442\u043E\u0440\u044B\u0445 {1} \u043D\u043E\u0432\u044B\u0445, \u0438 {2} \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0442 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0435 OLAT. <br>\u0425\u043E\u0442\u0438\u0442\u0435 \u0438\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C {1} \u043D\u043E\u0432\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0432 OLAT?
 import.example=\u0418\u043B\u043B\u044E\u0441\u0442\u0440\u0430\u0446\u0438\u044F - \u043F\u0440\u0438\u043C\u0435\u0440
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_sq.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_sq.properties
index 91709725355090085ff12164d1d45d978a5e9310..75816638b3149fdd369e2a4a871aff154d11d666 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_sq.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_sq.properties
@@ -3,8 +3,6 @@ error.columncount=Gabim n\u00EB rreshtin {0}\: nuk ka elemente t\u00EB mjaftuesh
 error.email=Gabim n\u00EB rreshtin {0}\: e-posta "{1}" \u00EBsht\u00EB e pavlefshme. Ju lutemi shkruani nj\u00EB adres\u00EB t\u00EB plot\u00EB dhe t\u00EB vlefshme t\u00EB e-post\u00EBs.
 error.email.douplicate=Gabim n\u00EB rreshtin {0}\: e-posta "{1}" tanim\u00EB \u00EBsht\u00EB p\u00EBrdorur nga shfryt\u00EBzuesi "{2}". 
 error.lang=Gabim n\u00EB rreshtin {0}\: gjuha \u00EBsht\u00EB "{1}" e pavlefshme. Ju lutemi p\u00EBrdorni nj\u00EB kod t\u00EB vlefsh\u00EBm t\u00EB gjuh\u00EBs.
-error.login={0}\: the user name "{1}" nuk ndjek konventat e OLAT-it. Ju lutemi nd\u00EBrro emrin e shfryt\u00EBzuesit.
-error.pwd=Gabim n\u00EB rreshtin {0}\: fjal\u00EBkalimi "{1}" nuk ndjek konventat e OLAT-it.  Ju lutemi nd\u00EBrro k\u00EBt\u00EB fjalkalim.
 form.importdata=Kolona t\u00EB kopjuara nga Exceli
 import.confirm={0} shfryt\u00EBzues n\u00EB tabel\u00EBn, {1} t\u00EB rinj\u00EB dhe {2} q\u00EB ekzistojn\u00EB. <br>A doni t'i importoni shfryt\u00EBzuesit {1} e rinj\u00EB n\u00EB OLAT?
 import.example=Imazh shembull
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_zh_CN.properties
index 53291db4c3a1fe274addc490d2962f13c9d5893f..b839c86d22e2dd27476f9340738b558de5ec2883 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_zh_CN.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_zh_CN.properties
@@ -7,10 +7,9 @@ error.emptyform=\u8BF7\u586B\u5165\u6B64\u5B57\u6BB5\u3002
 error.lang=\u5728\u7B2C{0}\u884C\u4E2D\u51FA\u9519\uFF1A\u8BED\u8A00\u201C{1}\u201D\u65E0\u6548\u3002\u8BF7\u4F7F\u7528\u4E00\u4E2A\u6709\u6548\u7684\u8BED\u8A00\u7F16\u7801\u3002
 error.length=\u9519\u8BEF\u53D1\u751F\u4E8E{0}\u884C\:\u5C5E\u6027\u503C"{1}"\u8D85\u51FA127\u4E2A\u5B57\u7B26\u3002
 error.lengthorformat=\u53D1\u751F\u4E8E{0}\u884C{1}\u5217\u7684\u9519\u8BEF\uFF1A{2}
-error.login=\u5728\u7B2C{0}\u884C\u4E2D\u51FA\u9519\uFF1A\u7528\u6237\u540D\u201C{1}\u201D\u672A\u9075\u5FAAOLAT\u7684\u7EA6\u5B9A\uFF0C\u8BF7\u4FEE\u6539\u8BE5\u7528\u6237\u540D
+error.login=\u5728\u7B2C{0}\u884C\u4E2D\u51FA\u9519\uFF1A{1}
 error.login.douplicate=\u9519\u8BEF\u53D1\u751F\u4E8E{0}\u884C\uFF1A\u7528\u6237\u540D"{1}"\u81F3\u5C11\u5DF2\u7ECF\u51FA\u73B0\u4E24\u6B21\uFF0C\u7528\u6237\u540D\u5FC5\u987B\u552F\u4E00\uFF01
 error.mandatory=\u9519\u8BEF\u53D1\u751F\u4E8E{0}\u884C\uFF1A\u5C5E\u6027"{1}"\u662F\u4EBA\u5DE5\u64CD\u4F5C\u7684\u3002
-error.pwd=\u5728\u7B2C{0}\u884C\u4E2D\u51FA\u9519\uFF1A\u5BC6\u7801\u201C{1}\u201D\u672A\u9075\u5FAAOLAT\u7684\u7EA6\u5B9A\uFF0C\u8BF7\u6539\u53D8\u8BE5\u5BC6\u7801
 form.importdata=\u4ECEExcel\u4E2D\u590D\u5236
 formatexplanation.part1=\u6839\u636E\u4E0B\u9762\u7684\u56FE\u4F8B\u4F7F\u7528Excel(\u6216\u8005OpenOffice)\u5BFC\u5165\u7528\u6237\u6570\u636E<br><ul>
 formatexplanation.part2.cancreatepassword=\u7528\u6237\u540D\uFF0C\u5BC6\u7801\uFF0C\u4F7F\u7528\u8BED\u8A00{0}.</li><li>\u5982\u679C\u201C\u5BC6\u7801\u201D\u90E8\u5206\u4ECD\u7136\u662F\u7A7A\u7684\uFF0C\u90A3\u4E48\u4EE5\u540E\u60A8\u4E5F\u8981\u63D0\u4F9B\u7528\u6237\u7684\u5BC6\u7801.</li>
diff --git a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_zh_TW.properties
index 75ac847422423529212f8cf7906da11683070a29..f2e74315c31623303daaff6e4c948386ced66b59 100644
--- a/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_zh_TW.properties
+++ b/src/main/java/org/olat/admin/user/imp/_i18n/LocalStrings_zh_TW.properties
@@ -7,10 +7,9 @@ error.emptyform=\u9019\u500B\u8868\u55AE\u4E0D\u80FD\u7A7A\u767D\u3002
 error.lang=\u932F\u8AA4\u5728\u7B2C {0} \u884C\uFF1A\u8A9E\u8A00 "{1}" \u662F\u7121\u6548\u7684\u3002\u8ACB\u4F7F\u7528\u4E00\u500B\u6709\u6548\u7684\u8A9E\u8A00\u4EE3\u78BC\u3002
 error.length=\u932F\u8AA4\u5728\u7B2C {0} \u884C\: \u5C6C\u6027\u503C "{1}" \u8D85\u904E 127 \u500B\u5B57\u5143\u3002
 error.lengthorformat=\u932F\u8AA4\u5728\u7B2C {0} \u884C\u7B2C {1} \u6B04\: {2}
-error.login=\u932F\u8AA4\u5728\u7B2C {0} \u884C\uFF1A\u4F7F\u7528\u8005\u540D\u7A31 "{1}" \u672A\u9075\u5FAA OLAT \u7684\u898F\u5B9A\u3002\u8ACB\u66F4\u6539\u8A72\u4F7F\u7528\u8005\u540D\u7A31\u3002
+error.login=\u932F\u8AA4\u5728\u7B2C {0} \u884C\uFF1A{1}
 error.login.douplicate=\u932F\u8AA4\u5728\u7B2C {0} \u884C\: \u4F7F\u7528\u8005\u540D\u7A31 "{1}" \u91CD\u8907\uFF0C\u5FC5\u9808\u552F\u4E00\u3002
 error.mandatory=\u932F\u8AA4\u5728\u7B2C {0} \u884C\: \u5C6C\u6027 "{1}" \u662F\u5FC5\u586B\u7684\u3002
-error.pwd=\u932F\u8AA4\u5728\u7B2C {0} \u884C\uFF1A\u5BC6\u78BC "{1}" \u672A\u9075\u5FAA OLAT \u7684\u898F\u5B9A\u3002\u8ACB\u66F4\u6539\u8A72\u5BC6\u78BC\u3002
 form.importdata=\u5F9E Excel \u8907\u88FD\u8CC7\u6599\u5217
 formatexplanation.part1=\u4F9D\u7167\u5E95\u4E0B\u7684\u5716\u7247\uFF08\u7528\u6ED1\u9F20\u5728\u5716\u4F8B\u4E0A\u9EDE\u4E00\u4E0B\uFF09\u4F7F\u7528 Excel (\u6216 OpenOffice)\u3002<br><ul>
 formatexplanation.part2.cancreatepassword=\u4F7F\u7528\u8005\u540D\u7A31, \u5BC6\u78BC, \u8A9E\u8A00{0}\u3002 </li><li>\u5982\u679C\u6B04\u4F4D "\u5BC6\u78BC" \u4FDD\u6301\u7A7A\u767D\uFF0C\u4E4B\u5F8C\u60A8\u5FC5\u9808\u63D0\u4F9B\u8A72\u4F7F\u7528\u8005\u4E00\u500B\u5BC6\u78BC\u3002</li>
diff --git a/src/main/java/org/olat/basesecurity/BaseSecurity.java b/src/main/java/org/olat/basesecurity/BaseSecurity.java
index 7703b432b1432a12f29490fb3a85bde172f22643..a91cad67e00627570e52bf2832d4c2829fde97de 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurity.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurity.java
@@ -351,10 +351,12 @@ public interface BaseSecurity {
 	 * Check if the password is allowed.
 	 * 
 	 * @param identity
+	 * @param provider
 	 * @param password
+	 * @param historyLength
 	 * @return
 	 */
-	public boolean checkCredentialHistory(Identity identity, String provider, String password);
+	public boolean checkCredentialHistory(Identity identity, String provider, String password, int historyLength);
 	
 	/**
 	 * 
diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
index 9bf9810d7b63bfa646334ca3b672b5f88986ee68..e35c7ec98ebc0e78c0ecb328728397292000aa9a 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
@@ -955,9 +955,8 @@ public class BaseSecurityManager implements BaseSecurity, UserDataDeletable {
 	}
 
 	@Override
-	public boolean checkCredentialHistory(Identity identity, String provider, String password) {
+	public boolean checkCredentialHistory(Identity identity, String provider, String password, int historyLength) {
 		boolean ok = true;
-		int historyLength = loginModule.getPasswordHistory();
 		if(historyLength > 0) {
 			List<AuthenticationHistory> credentialHistory = authenticationHistoryDao
 					.loadHistory(identity, provider, 0, historyLength);
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormItemImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormItemImpl.java
index 95d18e6ca62064a9f2a3827780a160b93fa7ff1a..34d2116e4b17b027f8191ffa08fa7c40eb1916fb 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormItemImpl.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/FormItemImpl.java
@@ -623,7 +623,7 @@ public abstract class FormItemImpl implements FormItem, InlineElement {
 	}
 	
 	/**
-	 * @see org.olat.core.gui.components.form.flexible.FormComponent#validate(java.util.List)
+	 * @see org.olat.core.gui.components.form.flexible.FormComponent#validate(java.util.List, Identity)
 	 */
 	@Override
 	public void validate(List<ValidationStatus> validationResults) {
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/JSDateChooser.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/JSDateChooser.java
index ceca30d10db11be9d906c90e20f042536dbdb189..9f8a5abef784b4bc36133c02e2629ed1e42da8c4 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/JSDateChooser.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/JSDateChooser.java
@@ -123,7 +123,7 @@ public class JSDateChooser extends TextElementImpl implements DateChooser {
 	}
 
 	/**
-	 * @see org.olat.core.gui.components.form.flexible.elements.AbstractTextElement#validate(java.util.List)
+	 * @see org.olat.core.gui.components.form.flexible.elements.AbstractTextElement#validate(java.util.List, Identity)
 	 */
 	@Override
 	public void validate(List<ValidationStatus> validationResults) {
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/CustomfieldsFormController.java b/src/main/java/org/olat/course/nodes/projectbroker/CustomfieldsFormController.java
index 0555e48371753a2a7b7c5e216cedb61233878ce9..d4a3aa9ef61d7c8c6a617ad7ebed615fd0f2899c 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/CustomfieldsFormController.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/CustomfieldsFormController.java
@@ -90,7 +90,7 @@ public class CustomfieldsFormController extends FormBasicController {
 	}
 
 	/**
-	 * @see org.olat.core.gui.components.Form#validate(org.olat.core.gui.UserRequest)
+	 * @see org.olat.core.gui.components.Form#validate(org.olat.core.gui.UserRequest, Identity)
 	 */
 	public boolean validate() {
 		return true;
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/OptionsFormController.java b/src/main/java/org/olat/course/nodes/projectbroker/OptionsFormController.java
index 65ca66c7eea1bd838d4c875143661b4290f9d6cd..dedefe10d55addd725d4c3f576868296461566b6 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/OptionsFormController.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/OptionsFormController.java
@@ -73,7 +73,7 @@ public class OptionsFormController extends FormBasicController {
 	}
 
 	/**
-	 * @see org.olat.core.gui.components.Form#validate(org.olat.core.gui.UserRequest)
+	 * @see org.olat.core.gui.components.Form#validate(org.olat.core.gui.UserRequest, Identity)
 	 */
 	public boolean validate() {
 		return true;
diff --git a/src/main/java/org/olat/course/nodes/st/EditScoreCalculationEasyForm.java b/src/main/java/org/olat/course/nodes/st/EditScoreCalculationEasyForm.java
index 67588bc280dabeb4fad871de0fd64fedbe1b807c..14aeb3f3683757ca593686ed05217a9f10bba383 100644
--- a/src/main/java/org/olat/course/nodes/st/EditScoreCalculationEasyForm.java
+++ b/src/main/java/org/olat/course/nodes/st/EditScoreCalculationEasyForm.java
@@ -235,7 +235,7 @@ public class EditScoreCalculationEasyForm extends FormBasicController {
 	}
 
 	/**
-	 * @see org.olat.core.gui.components.Form#validate(org.olat.core.gui.UserRequest)
+	 * @see org.olat.core.gui.components.Form#validate(org.olat.core.gui.UserRequest, Identity)
 	 */
 	@Override
 	public boolean validateFormLogic(UserRequest ureq) {
diff --git a/src/main/java/org/olat/login/LoginModule.java b/src/main/java/org/olat/login/LoginModule.java
index 0224673316472132d5eae2add0d53eb56dc8b44f..5c767b5cec3af38cfd06b9d15b51de43105784a2 100644
--- a/src/main/java/org/olat/login/LoginModule.java
+++ b/src/main/java/org/olat/login/LoginModule.java
@@ -26,14 +26,17 @@
 package org.olat.login;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
+import org.apache.logging.log4j.Logger;
 import org.olat.basesecurity.OrganisationRoles;
 import org.olat.core.configuration.AbstractSpringModule;
 import org.olat.core.id.Roles;
-import org.apache.logging.log4j.Logger;
 import org.olat.core.logging.StartupException;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.Encoder;
@@ -65,7 +68,26 @@ public class LoginModule extends AbstractSpringModule {
 		OrganisationRoles.poolmanager, OrganisationRoles.linemanager	
 	};
 	
+	public static final String DISABLED = "disabled";
+	public static final String FORBIDDEN = "forbiddden";
+	public static final String AT_LEAST_1 = "atLeast1";
+	public static final String AT_LEAST_2 = "atLeast2";
+	public static final String AT_LEAST_3 = "atLeast3";
+	public static final String VALIDATE_SEPARATELY = "validateSeparately";
+	
+	private static final String USERNAME_REGEX = "username.regex";
 	private static final String CHANGE_ONCE = "password.change.once";
+	private static final String MIN_LENGTH = "password.min.length";
+	private static final String MAX_LENGTH = "password.max.length";
+	private static final String LETTERS = "password.letters";
+	private static final String LETTERS_UPPER = "password.letters.upper";
+	private static final String LETTERS_LOWER = "password.letters.lower";
+	private static final String DIGITS_SPECIALS = "password.digits.specials";
+	private static final String DIGITS = "password.digits";
+	private static final String SPECIALS = "password.specials";
+	private static final String FORBIDDEN_USERNAME = "password.forbidden.username";
+	private static final String FORBIDDEN_FIRSTNAME = "password.forbidden.firstname";
+	private static final String FORBIDDEN_LASTNAME = "password.forbidden.lastname";
 	private static final String MAX_AGE = "password.max.age";
 	private static final String MAX_AGE_AUTHOR = "password.max.age.author";
 	private static final String MAX_AGE_GROUPMANAGER = "password.max.age.groupmanager";
@@ -91,6 +113,10 @@ public class LoginModule extends AbstractSpringModule {
 	private int attackPreventionMaxAttempts;
 	@Value("${login.AttackPreventionTimeoutmin:5}")
 	private int attackPreventionTimeout;
+	
+	@Value("${username.regex}")
+	private String usernameRegex;
+	private Pattern usernamePattern;
 
 	@Value("${password.change.valid.hours.gui}")
 	private Integer validUntilHoursGui;
@@ -100,6 +126,29 @@ public class LoginModule extends AbstractSpringModule {
 	@Value("${password.change.once:false}")
 	private boolean passwordChangeOnce;
 	
+	@Value("${password.min.length}")
+	private int passwordMinLength;
+	@Value("${password.max.length}")
+	private int passwordMaxLength;
+	@Value("${password.letters}")
+	private String passwordLetters;
+	@Value("${password.letters.uppercase}")
+	private String passwordLettersUppercase;
+	@Value("${password.letters.lowercase}")
+	private String passwordLettersLowercase;
+	@Value("${password.digits.special.signs}")
+	private String passwordDigitsAndSpecialSigns;
+	@Value("${password.digits}")
+	private String passwordDigits;
+	@Value("${password.special.signs}")
+	private String passwordSpecialSigns;
+	@Value("${password.forbidden.username}")
+	private boolean passwordUsernameForbidden;
+	@Value("${password.forbidden.firstname}")
+	private boolean passwordFirstnameForbidden;
+	@Value("${password.forbidden.lastname}")
+	private boolean passwordLastnameForbidden;
+	
 	@Value("${password.max.age}")
 	private int passwordMaxAge;
 	@Value("${password.max.age.author}")
@@ -161,6 +210,7 @@ public class LoginModule extends AbstractSpringModule {
 		failedLoginCache = coordinatorManager.getCoordinator().getCacher().getCache(LoginModule.class.getSimpleName(), "blockafterfailedattempts");
 				
 		updateProperties();
+		validateProperties();
 		
 		boolean defaultProviderFound = false;
 		for (Iterator<AuthenticationProvider> iterator = authenticationProviders.iterator(); iterator.hasNext();) {
@@ -177,6 +227,32 @@ public class LoginModule extends AbstractSpringModule {
 		}
 	}
 
+	private void validateProperties() {
+		validateValidationConfig("password.letters", passwordLetters,
+				Arrays.asList(DISABLED, FORBIDDEN, AT_LEAST_1, AT_LEAST_2, AT_LEAST_3, VALIDATE_SEPARATELY));
+		validateValidationConfig("password.letters.uppercase", passwordLettersUppercase,
+				Arrays.asList(DISABLED, FORBIDDEN, AT_LEAST_1, AT_LEAST_2, AT_LEAST_3));
+		validateValidationConfig("password.letters.lowercase", passwordLettersLowercase,
+				Arrays.asList(DISABLED, FORBIDDEN, AT_LEAST_1, AT_LEAST_2, AT_LEAST_3));
+		validateValidationConfig("password.digits.special.signs", passwordDigitsAndSpecialSigns,
+				Arrays.asList(DISABLED, FORBIDDEN, AT_LEAST_1, AT_LEAST_2, AT_LEAST_3, VALIDATE_SEPARATELY));
+		validateValidationConfig("password.digits", passwordDigits,
+				Arrays.asList(DISABLED, FORBIDDEN, AT_LEAST_1, AT_LEAST_2, AT_LEAST_3));
+		validateValidationConfig("password.special.signs", passwordSpecialSigns,
+				Arrays.asList(DISABLED, FORBIDDEN, AT_LEAST_1, AT_LEAST_2, AT_LEAST_3));
+	}
+	
+	private void validateValidationConfig(String configName, String configValue, List<String> validValues) {
+		if (!validValues.contains(configValue)) {
+			logInvalidValidationConfig(configName, configValue, validValues);
+		}
+	}
+	
+	private void logInvalidValidationConfig(String configName, String configValue, List<String> validValues) {
+		log.error("Invalid configuration for " + configName + " (value = " + configValue + "). Valid values are: " 
+				+ validValues.stream().collect(Collectors.joining(", ")));
+	}
+
 	@Override
 	protected void initFromChangedProperties() {
 		updateProperties();
@@ -242,11 +318,71 @@ public class LoginModule extends AbstractSpringModule {
 			allowLoginUsingEmail = "true".equals(usernameOrEmailLogin);
 		}
 		
+		String usernameRegexObj = getStringPropertyValue(USERNAME_REGEX, true);
+		if(StringHelper.containsNonWhitespace(usernameRegexObj)) {
+			usernameRegex = usernameRegexObj;
+		}
+		
 		String changeOnce = getStringPropertyValue(CHANGE_ONCE, true);
 		if(StringHelper.containsNonWhitespace(changeOnce)) {
 			passwordChangeOnce = "true".equals(changeOnce);
 		}
 		
+		String passwordMinLengthObj = getStringPropertyValue(MIN_LENGTH, true);
+		if(StringHelper.containsNonWhitespace(passwordMinLengthObj)) {
+			passwordMinLength = Integer.parseInt(passwordMinLengthObj);
+		}
+		
+		String passwordMaxLengthObj = getStringPropertyValue(MAX_LENGTH, true);
+		if(StringHelper.containsNonWhitespace(passwordMaxLengthObj)) {
+			passwordMaxLength = Integer.parseInt(passwordMaxLengthObj);
+		}
+		
+		String passwordLettersObj = getStringPropertyValue(LETTERS, true);
+		if(StringHelper.containsNonWhitespace(passwordLettersObj)) {
+			passwordLetters = passwordLettersObj;
+		}
+		
+		String passwordLettersUppercaseObj = getStringPropertyValue(LETTERS_UPPER, true);
+		if(StringHelper.containsNonWhitespace(passwordLettersUppercaseObj)) {
+			passwordLettersUppercase = passwordLettersUppercaseObj;
+		}
+		
+		String passwordLettersLowercaseObj = getStringPropertyValue(LETTERS_LOWER, true);
+		if(StringHelper.containsNonWhitespace(passwordLettersLowercaseObj)) {
+			passwordLettersLowercase = passwordLettersLowercaseObj;
+		}
+		
+		String passwordDigitsAndSpecialSignsObj = getStringPropertyValue(DIGITS_SPECIALS, true);
+		if(StringHelper.containsNonWhitespace(passwordDigitsAndSpecialSignsObj)) {
+			passwordDigitsAndSpecialSigns = passwordDigitsAndSpecialSignsObj;
+		}
+		
+		String passwordDigitsObj = getStringPropertyValue(DIGITS, true);
+		if(StringHelper.containsNonWhitespace(passwordDigitsObj)) {
+			passwordDigits = passwordDigitsObj;
+		}
+		
+		String passwordSpecialSignsObj = getStringPropertyValue(SPECIALS, true);
+		if(StringHelper.containsNonWhitespace(passwordSpecialSignsObj)) {
+			passwordSpecialSigns = passwordSpecialSignsObj;
+		}
+		
+		String passwordUsernameForbiddenObj = getStringPropertyValue(FORBIDDEN_USERNAME, true);
+		if(StringHelper.containsNonWhitespace(passwordUsernameForbiddenObj)) {
+			passwordUsernameForbidden = "true".equals(passwordUsernameForbiddenObj);
+		}
+		
+		String passwordFirstnameForbiddenObj = getStringPropertyValue(FORBIDDEN_FIRSTNAME, true);
+		if(StringHelper.containsNonWhitespace(passwordFirstnameForbiddenObj)) {
+			passwordFirstnameForbidden = "true".equals(passwordFirstnameForbiddenObj);
+		}
+		
+		String passwordLastnameForbiddenObj = getStringPropertyValue(FORBIDDEN_LASTNAME, true);
+		if(StringHelper.containsNonWhitespace(passwordLastnameForbiddenObj)) {
+			passwordLastnameForbidden = "true".equals(passwordLastnameForbiddenObj);
+		}
+		
 		int validUntilHoursGuiInt = getIntPropertyValue("password.change.valid.hours.gui");
 		if (validUntilHoursGuiInt > 0) {
 			validUntilHoursGui = validUntilHoursGuiInt;
@@ -447,6 +583,23 @@ public class LoginModule extends AbstractSpringModule {
 		setStringProperty("login.using.username.or.email.enabled", Boolean.toString(allow), true);
 	}
 	
+	public String getUsernameRegex() {
+		return usernameRegex;
+	}
+
+	public void setUsernameRegex(String usernameRegex) {
+		this.usernameRegex = usernameRegex;
+		this.usernamePattern = null;
+		setStringProperty(USERNAME_REGEX, usernameRegex, true);
+	}
+
+	public Pattern getUsernamePattern() {
+		if (usernamePattern == null) {
+			usernamePattern = Pattern.compile(usernameRegex);
+		}
+		return usernamePattern;
+	}
+
 	public Integer getValidUntilHoursGui() {
 		return validUntilHoursGui;
 	}
@@ -474,6 +627,105 @@ public class LoginModule extends AbstractSpringModule {
 		setStringProperty(CHANGE_ONCE, passwordChangeOnce ? "true" : "false", true);
 	}
 	
+	public int getPasswordMinLength() {
+		return passwordMinLength;
+	}
+
+	public void setPasswordMinLength(int passwordMinLength) {
+		this.passwordMinLength = passwordMinLength;
+		setStringProperty(MIN_LENGTH, String.valueOf(passwordMinLength), true);
+	}
+
+	public int getPasswordMaxLength() {
+		return passwordMaxLength;
+	}
+
+	public void setPasswordMaxLength(int passwordMaxLength) {
+		this.passwordMaxLength = passwordMaxLength;
+		setStringProperty(MAX_LENGTH, String.valueOf(passwordMaxLength), true);
+	}
+
+	public String getPasswordLetters() {
+		return passwordLetters;
+	}
+
+	public void setPasswordLetters(String passwordLetters) {
+		this.passwordLetters = passwordLetters;
+		setStringProperty(LETTERS, String.valueOf(passwordLetters), true);
+	}
+
+	public String getPasswordLettersUppercase() {
+		return passwordLettersUppercase;
+	}
+
+	public void setPasswordLettersUppercase(String passwordLettersUppercase) {
+		this.passwordLettersUppercase = passwordLettersUppercase;
+		setStringProperty(LETTERS_UPPER, String.valueOf(passwordLettersUppercase), true);
+	}
+
+	public String getPasswordLettersLowercase() {
+		return passwordLettersLowercase;
+	}
+
+	public void setPasswordLettersLowercase(String passwordLettersLowercase) {
+		this.passwordLettersLowercase = passwordLettersLowercase;
+		setStringProperty(LETTERS_LOWER, String.valueOf(passwordLettersLowercase), true);
+	}
+
+	public String getPasswordDigitsAndSpecialSigns() {
+		return passwordDigitsAndSpecialSigns;
+	}
+
+	public void setPasswordDigitsAndSpecialSigns(String passwordDigitsAndSpecialSigns) {
+		this.passwordDigitsAndSpecialSigns = passwordDigitsAndSpecialSigns;
+		setStringProperty(DIGITS_SPECIALS, String.valueOf(passwordDigitsAndSpecialSigns), true);
+	}
+
+	public String getPasswordDigits() {
+		return passwordDigits;
+	}
+
+	public void setPasswordDigits(String passwordDigits) {
+		this.passwordDigits = passwordDigits;
+		setStringProperty(DIGITS, String.valueOf(passwordDigits), true);
+	}
+
+	public String getPasswordSpecialSigns() {
+		return passwordSpecialSigns;
+	}
+
+	public void setPasswordSpecialSigns(String passwordSpecialSigns) {
+		this.passwordSpecialSigns = passwordSpecialSigns;
+		setStringProperty(SPECIALS, String.valueOf(passwordSpecialSigns), true);
+	}
+
+	public boolean isPasswordUsernameForbidden() {
+		return passwordUsernameForbidden;
+	}
+
+	public void setPasswordUsernameForbidden(boolean passwordUsernameForbidden) {
+		this.passwordUsernameForbidden = passwordUsernameForbidden;
+		setStringProperty(FORBIDDEN_USERNAME, Boolean.toString(passwordUsernameForbidden), true);
+	}
+
+	public boolean isPasswordFirstnameForbidden() {
+		return passwordFirstnameForbidden;
+	}
+
+	public void setPasswordFirstnameForbidden(boolean passwordFirstnameForbidden) {
+		this.passwordFirstnameForbidden = passwordFirstnameForbidden;
+		setStringProperty(FORBIDDEN_FIRSTNAME, Boolean.toString(passwordFirstnameForbidden), true);
+	}
+
+	public boolean isPasswordLastnameForbidden() {
+		return passwordLastnameForbidden;
+	}
+
+	public void setPasswordLastnameForbidden(boolean passwordLastnameForbidden) {
+		this.passwordLastnameForbidden = passwordLastnameForbidden;
+		setStringProperty(FORBIDDEN_LASTNAME, Boolean.toString(passwordLastnameForbidden), true);
+	}
+
 	public boolean isPasswordAgePolicyConfigured() {
 		return passwordMaxAge > 0 || passwordMaxAgeAuthor > 0
 				|| passwordMaxAgeGroupManager > 0 || passwordMaxAgePoolManager > 0
diff --git a/src/main/java/org/olat/login/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/login/_i18n/LocalStrings_de.properties
index abfc5eeda10ac968b1a9859073104927ed7824ca..db625558b2f5e1c454e89857de0a016621a7f9bc 100644
--- a/src/main/java/org/olat/login/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/login/_i18n/LocalStrings_de.properties
@@ -40,17 +40,42 @@ accesskey.top=$org.olat.core.commons.fullWebApp\:accesskey.top
 accesskey.topnav=$org.olat.core.commons.fullWebApp\:accesskey.topnav
 admin.menu.title=Gast und Einladung
 admin.menu.title.alt=$\:admin.menu.title
-
 disable.history=ausgeschaltet
-password.after=f\uFFFDr {0} \uFFFDnderungen
-password.history=Verwendung von vorherigen Passw\uFFFDrtern verhindern
-admin.password.menu.title=Passwort-Richtlinien
-admin.password.menu.title.alt=Richtlinien \uFFFDber die \uFFFDnderung von Passw\uFFFDrtern
+password.after=f\u00FCr {0} \u00C4nderungen
+password.history=Verwendung von vorherigen Passw\u00F6rtern verhindern
+admin.password.menu.title=Passw\u00F6rter
+admin.password.menu.title.alt=Passw\u00F6rter
+admin.password.syntax=Syntax-Regeln
+admin.password.policy=\u00C4nderungsrichtlinien
+admin.syntax.digits.or.specials=Ziffern und Sonderzeichen separat definieren
+admin.syntax.digits.specials=Ziffern und Sonderzeichen
+admin.syntax.digits=Ziffern
+admin.syntax.forbidden.firstname=Vorname des Benutzers
+admin.syntax.forbidden.lastname=Nachname des Benutzers
+admin.syntax.forbidden.username=Benutzername
+admin.syntax.forbidden.values=Nicht erlaubte Werte
+admin.syntax.forbidden=Nicht erlaubt
+admin.syntax.letters.lower.upper=Gross- und Kleinbuchstaben separat definieren
+admin.syntax.letters.lowercase=Kleinbuchstaben
+admin.syntax.letters.uppercase=Grossbuchstaben
+admin.syntax.letters=Buchstaben
+admin.syntax.max.length=Maximall\u00E4nge
+admin.syntax.min.1=Mindestends 1
+admin.syntax.min.2=Mindestends 2
+admin.syntax.min.3=Mindestends 3
+admin.syntax.min.length=Minimall\u00E4nge
+admin.syntax.permitted=Erlaubt
+admin.syntax.preview.description=Validieren Sie ein Passwort gegen\u00FCber den eingestellten Syntax-Regeln. Folgende Regeln sind aktiv:{0}
+admin.syntax.preview.password=Passwort
+admin.syntax.preview.validate=Validieren
+admin.syntax.preview.title=Passwort Syntax Validierung
+admin.syntax.preview=Vorschau
+admin.syntax.specials=Sonderzeichen
 change.once=Passwort \u00E4ndern beim ersten Login
 max.age=Neues Passwort erzwingen nach
 max.age.hint=in Tagen
-max.age.description=Sie k\uFFFDnnen hier festlegen wie oft ein Benutzer sein Passwort \uFFFDndern muss und ob ein Passwort wiederverwendet werden kann. Die Lebensdauer des Passwortes kann pro Rolle festgelegt werden.
-max.age.author=... f\uFFFDr Autoren
+max.age.description=Sie k\u00F6nnen hier festlegen wie oft ein Benutzer sein Passwort \u00E4ndern muss und ob ein Passwort wiederverwendet werden kann. Die Lebensdauer des Passwortes kann pro Rolle festgelegt werden.
+max.age.author=... f\u00FCr Autoren
 max.age.groupmanager=... Gruppenverwalter
 max.age.poolmanager=...  Fragenpoolverwalter
 max.age.usermanager=... Benutzerverwalter
@@ -63,11 +88,36 @@ max.age.lecturemanager=... Lektionenverwalter
 max.age.principal=... Principal
 max.age.administrator=... Administrator
 max.age.sysadmin=... Systemadministrator
-password.policy.title=Passwort-Richtlinien
 password.change.valid.until.gui=G\u00FCltigkeitsdauer Passwort\u00E4nderung in Stunden (GUI)
 password.change.valid.until.rest=G\u00FCltigkeitsdauer Passwort\u00E4nderung in Stunden (REST)
+password.rule.at.least.digits=Das Password muss mindestens {0} Ziffern beinhalten.
+password.rule.at.least.digits.specials=Das Password muss mindestens {0} Ziffern oder Sonderzeichen beinhalten.
+password.rule.at.least.letters=Das Password muss mindestens {0} Buchstaben beinhalten.
+password.rule.at.least.letters.lowercase=Das Password muss mindestens {0} Kleinbuchstaben beinhalten.
+password.rule.at.least.letters.uppercase=Das Password muss mindestens {0} Grossbuchstaben beinhalten.
+password.rule.at.least.specials=Das Password muss mindestens {0} Sonderzeichen beinhalten.
+password.rule.forbidden.digits=Das Passwort darf keine Ziffern beinhalten.
+password.rule.forbidden.digits.specials=Das Passwort darf keine Ziffern und keine Sonderzeichen beinhalten.
+password.rule.forbidden.letters=Das Passwort darf keine Buchstaben beinhalten.
+password.rule.forbidden.letters.lowercase=Das Passwort darf keine Kleinbuchstaben beinhalten.
+password.rule.forbidden.letters.uppercase=Das Passwort darf keine Grossbuchstaben beinhalten.
+password.rule.forbidden.specials=Das Passwort darf keine Sonderzeichen beinhalten.
+password.rule.forbidden.username=Das Passwort darf nicht den Benutzernamen beinhalten.
+password.rule.forbidden.user.firstname=Das Passwort darf nicht den Vornamen beinhalten.
+password.rule.forbidden.user.lastname=Das Passwort darf nicht den Nachnamen beinhalten.
+password.rule.history=Sie d\u00FCrfen nicht ein Passwort, das Sie schon hatten, wieder verwenden.
+password.rule.length=Das Password muss insgesamt zwischen {0} und {1} Zeichen lang sein.
+password.rule.permitted.digits.specials=Ziffern und Sonderzeichen sind zul\u00E4ssig.
+password.rule.permitted.digits=Ziffern sind zul\u00E4ssig.
+password.rule.permitted.letters.lowercase=Kleinbuchstaben sind zul\u00E4ssig.
+password.rule.permitted.letters.uppercase=Grossbuchstaben sind zul\u00E4ssig.
+password.rule.permitted.letters=Buchstaben sind zul\u00E4ssig.
+password.rule.permitted.specials=Sonderzeichen sind zul\u00E4ssig.
+username.rule.syntax=$org.olat.user\:form.checkUsername
+username.rule.blacklist=$org.olat.registration\:form.check6
+username.rule.in.use=$org.olat.registration\:form.check6
+error.password.length.lower=Die Maximall\u00E4nge muss gr\u00F6sser sein als die Minimall\u00E4nge.
 error.wrong.int=Falsches Zahlenformat.
-
 authentication.provider.description=Geh\u00F6ren Sie keiner der oben aufgelisteten Institutionen an oder haben ein lokales Nutzerkonto?
 authentication.provider.linkText=Anmelden mit OpenOLAT Konto 
 browsercheck.bestresults.newerversion=oder neuere Version
diff --git a/src/main/java/org/olat/login/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/login/_i18n/LocalStrings_en.properties
index 11464d9aabd15f7afd47caf8099a51a56e158142..b8834d6f307bd4cc3d8c4d2fef9372d2c3a9f314 100644
--- a/src/main/java/org/olat/login/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/login/_i18n/LocalStrings_en.properties
@@ -40,12 +40,37 @@ accesskey.top=$org.olat.core.commons.fullWebApp\:accesskey.top
 accesskey.topnav=$org.olat.core.commons.fullWebApp\:accesskey.topnav
 admin.menu.title=Guest and invitation
 admin.menu.title.alt=$\:admin.menu.title
-
 disable.history=disabled
 password.after=for {0} changes
 password.history=Prevent reuse of previous passwords
-admin.password.menu.title=Password policy
-admin.password.menu.title.alt=Policy about changing of passwords
+admin.password.menu.title.alt=Passwords
+admin.password.menu.title=Passwords
+admin.password.policy=Change policies
+admin.password.syntax=Syntax rules
+admin.syntax.digits.or.specials=Separat definition of digits and special signs
+admin.syntax.digits.specials=Digits and special signs
+admin.syntax.digits=Digits
+admin.syntax.forbidden.firstname=Firstname of user
+admin.syntax.forbidden.lastname=Lastname of user
+admin.syntax.forbidden.username=Username
+admin.syntax.forbidden.values=Forbidden values
+admin.syntax.forbidden=Forbidden
+admin.syntax.letters.lower.upper=Separat definition of uppercase and lowercase letters
+admin.syntax.letters.lowercase=Lowercase letters
+admin.syntax.letters.uppercase=Uppercase letters
+admin.syntax.letters=Letters
+admin.syntax.max.length=Maximum length
+admin.syntax.min.1=At least 1
+admin.syntax.min.2=At least 2
+admin.syntax.min.3=At least 3
+admin.syntax.min.length=Minimum length
+admin.syntax.permitted=Permitted
+admin.syntax.preview.description=Validate a password against the selected rules. The rules are:{0}
+admin.syntax.preview.password=Password
+admin.syntax.preview.validate=Validate
+admin.syntax.preview.title=Validation of psswort syntax
+admin.syntax.preview=Preview
+admin.syntax.specials=Special signs
 change.once=Change password on first login
 max.age=Enforce new password after
 max.age.hint=in days
@@ -63,9 +88,35 @@ max.age.learnresourcemanager=... for learning resource manager
 max.age.principal=... for principal
 max.age.administrator=... for administrator
 max.age.sysadmin=... for system administrator
-password.policy.title=Password policies
 password.change.valid.until.gui=Password change validity period in hours (GUI)
 password.change.valid.until.rest=Password change validity period in hours (REST)
+password.rule.at.least.digits.specials=The password has to contain at least {0} digits or special signs.
+password.rule.at.least.digits=The password has to contain at least {0} digits.
+password.rule.at.least.letters.lowercase=The password has to contain at least {0} lowercase letters.
+password.rule.at.least.letters.uppercase=The password has to contain at least {0} uppercase letters.
+password.rule.at.least.letters=The password has to contain at least {0} letters.
+password.rule.at.least.specials=The password has to contain at least {0} special signs.
+password.rule.forbidden.digits.specials=The password must not contain any digits or special characters.
+password.rule.forbidden.digits=The password must not contain any digits.
+password.rule.forbidden.letters.lowercase=The password must not contain any lowercase letters.
+password.rule.forbidden.letters.uppercase=The password must not contain any uppercase letters.
+password.rule.forbidden.letters=The password must not contain any letters.
+password.rule.forbidden.specials=The password must not contain any special signs.
+password.rule.forbidden.user.firstname=The password must not contain the first name.
+password.rule.forbidden.user.lastname=The password must not contain the last name.
+password.rule.forbidden.username=The password must not contain the username.
+password.rule.history=You cannot use a password you already used in the past
+password.rule.length=The password has to contain at least {0} and at most {1} characters.
+password.rule.permitted.digits.specials=Digits and special signs are permitted.
+password.rule.permitted.digits=Digits signs are permitted.
+password.rule.permitted.letters.lowercase=Lowercase letters are permitted.
+password.rule.permitted.letters.uppercase=Uppercase letters are permitted.
+password.rule.permitted.letters=Letters and special signs are permitted.
+password.rule.permitted.specials=Special signs are permitted.
+username.rule.syntax=$org.olat.user\:form.checkUsername
+username.rule.blacklist=$org.olat.registration\:form.check6
+username.rule.in.use=$org.olat.registration\:form.check6
+error.password.length.lower=The maximal length has to be higher than the minimum length.
 error.wrong.int=Wrong numerical format
 
 authentication.provider.description=Don't you belong to one of the institutions mentioned above or have a local user account?
diff --git a/src/main/java/org/olat/login/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/login/_i18n/LocalStrings_fr.properties
index 79e681facdee5b66a6c35f24ce48500f8a1478ed..780a13bac02c3b71649dd9ea9279b07678db2f68 100644
--- a/src/main/java/org/olat/login/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/login/_i18n/LocalStrings_fr.properties
@@ -40,8 +40,8 @@ accesskey.top=$org.olat.core.commons.fullWebApp\:accesskey.top
 accesskey.topnav=$org.olat.core.commons.fullWebApp\:accesskey.topnav
 admin.menu.title=Invit\u00E9s et invitations
 admin.menu.title.alt=$\:admin.menu.title
-admin.password.menu.title=R\u00E8gles concernant les mots de passes
-admin.password.menu.title.alt=R\u00E8gles concernant les changements de mots de passes
+admin.password.menu.title=Mots de passes
+admin.password.menu.title.alt=Mots de passes
 authentication.provider.description=N'appertenez-vous pas \u00E0 l'une des institutions mentionn\u00E9es ci-dessus ou n'avez-vous pas un compte utilisateur local?
 authentication.provider.linkText=Connectez-vous avec un compte OpenOLAT
 browsercheck.bestresults.newerversion=ou nouvelle version
@@ -135,7 +135,7 @@ password.after=pour {0} changements
 password.change.valid.until.gui=Dur\u00E9e de validit\u00E9 des mots de passes (UI)
 password.change.valid.until.rest=Dur\u00E9e de validit\u00E9 des mots de passes (REST)
 password.history=Pr\u00E9venir la r\u00E9utilisation des mots de passes pr\u00E9c\u00E9dants
-password.policy.title=R\u00E8gles concernant les mots de passes
+password.rule.history=Vous ne pouvez pas r\u00E9utiliser un mot de passe que vous avez d\u00E9j\u00E0 utilis\u00E9 par le pass\u00E9.
 runonce.forced=Veuillez compl\u00E9ter toutes les indications et enregistrez le formulaire, s.v.p. .
 runonce.title=Modifications r\u00E9currentes / r\u00E9glages \u00E0 la premi\u00E8re connexion
 shib.redirect=Shibboleth Login
diff --git a/src/main/java/org/olat/login/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/login/_i18n/LocalStrings_pt_BR.properties
index 40a7f7e3b0a1c7807e9a28aacfdbb41087c14278..b23bc69730cd8e09f25569aee30ac60b9886db31 100644
--- a/src/main/java/org/olat/login/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/login/_i18n/LocalStrings_pt_BR.properties
@@ -38,8 +38,8 @@ accesskey.top=$org.olat.core.commons.fullWebApp\:accesskey.top
 accesskey.topnav=$org.olat.core.commons.fullWebApp\:accesskey.topnav
 admin.menu.title=Convidados e convites
 admin.menu.title.alt=$\:admin.menu.title
-admin.password.menu.title=Pol\u00EDtica de senha
-admin.password.menu.title.alt=Pol\u00EDtica sobre altera\u00E7\u00F5es de senhas
+admin.password.menu.title=Senha
+admin.password.menu.title.alt=Senhas
 authentication.provider.description=Voc\u00EA n\u00E3o pertence a uma das institui\u00E7\u00F5es mencionadas acima ou possui uma conta de usu\u00E1rio local?
 authentication.provider.linkText=Entrar com conta OpenOLAT
 browsercheck.bestresults.newerversion=ou vers\u00E3o mais atual 
@@ -131,7 +131,7 @@ password.after=para {0} mudan\u00E7as
 password.change.valid.until.gui=Per\u00EDodo de validade da mudan\u00E7a de senha em horas (GUI)
 password.change.valid.until.rest=Per\u00EDodo de validade da mudan\u00E7a de senha em horas (REST)
 password.history=Previnir reaproveitamento de senhas anteriores
-password.policy.title=Pol\u00EDticas de senhas
+password.rule.history=Voc\u00EA n\u00E3o pode usar uma senha que j\u00E1 usou no passado
 runonce.forced=Por favor, preencha este formul\u00E1rio e salve as configura\u00E7\u00F5es.
 runonce.title=Modifica\u00E7\u00F5es/Ajustes recorrentes ao entrar pela primeira vez
 shib.redirect=Shibboleth Login
diff --git a/src/main/java/org/olat/login/_spring/loginContext.xml b/src/main/java/org/olat/login/_spring/loginContext.xml
index 1db16d14b0902b9a790070b456f99ef08f7659b1..3b6172d019de3c46deabd413d1d51e83395b9993 100644
--- a/src/main/java/org/olat/login/_spring/loginContext.xml
+++ b/src/main/java/org/olat/login/_spring/loginContext.xml
@@ -74,10 +74,10 @@
 		<property name="order" value="8810" />
 		<property name="actionController">	
 			<bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype">
-				<property name="className" value="org.olat.login.ui.PasswordPolicyController"/>
+				<property name="className" value="org.olat.login.ui.PasswordAdminController"/>
 			</bean>
 		</property>
-		<property name="navigationKey" value="passwordpolicy" />
+		<property name="navigationKey" value="passwords" />
 		<property name="i18nActionKey" value="admin.password.menu.title"/>
 		<property name="i18nDescriptionKey" value="admin.password.menu.title.alt"/>
 		<property name="translationPackage" value="org.olat.login"/>
diff --git a/src/main/java/org/olat/login/auth/OLATAuthManager.java b/src/main/java/org/olat/login/auth/OLATAuthManager.java
index c74b27f0779150838c17a4dd9a160da586c46268..1b019807cb2869e1a2a69bcf0c070ed4ac998103 100644
--- a/src/main/java/org/olat/login/auth/OLATAuthManager.java
+++ b/src/main/java/org/olat/login/auth/OLATAuthManager.java
@@ -30,9 +30,9 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
+import org.apache.logging.log4j.Logger;
 import org.olat.basesecurity.Authentication;
 import org.olat.basesecurity.BaseSecurity;
-import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.basesecurity.IdentityRef;
 import org.olat.basesecurity.manager.AuthenticationDAO;
 import org.olat.core.commons.services.webdav.manager.WebDAVAuthManager;
@@ -41,7 +41,6 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.logging.AssertException;
-import org.apache.logging.log4j.Logger;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.Encoder.Algorithm;
 import org.olat.core.util.StringHelper;
@@ -63,6 +62,9 @@ import org.olat.login.LoginModule;
 import org.olat.login.OLATAuthenticationController;
 import org.olat.login.oauth.OAuthLoginModule;
 import org.olat.login.oauth.OAuthSPI;
+import org.olat.login.validation.PasswordValidationRulesFactory;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.UsernameValidationRulesFactory;
 import org.olat.registration.RegistrationManager;
 import org.olat.registration.TemporaryKey;
 import org.olat.shibboleth.ShibbolethDispatcher;
@@ -99,6 +101,10 @@ public class OLATAuthManager implements AuthenticationSPI {
 	private AuthenticationDAO authenticationDao;
 	@Autowired
 	private RegistrationManager registrationManager;
+	@Autowired
+	private PasswordValidationRulesFactory passwordRulesFactory;
+	@Autowired
+	private UsernameValidationRulesFactory usernameRulesFactory;
 	
 	/**
 	 * 
@@ -195,7 +201,16 @@ public class OLATAuthManager implements AuthenticationSPI {
 				}
 			}
 		}
-		return null;		
+		return null;
+	}
+	
+	public SyntaxValidator createUsernameSytaxValidator() {
+		return new SyntaxValidator(usernameRulesFactory.createRules(), false);
+	}
+	
+	
+	public SyntaxValidator createPasswordSytaxValidator() {
+		return new SyntaxValidator(passwordRulesFactory.createRules(), true);
 	}
 	
 	/**
@@ -344,24 +359,4 @@ public class OLATAuthManager implements AuthenticationSPI {
 		return changePassword(identity, identity, newPwd);
 	}
 	
-
-	/**
-	 * Check the credential history if configured and if the user
-	 * has not a LDAP credential.
-	 * 
-	 * @param identity The identity
-	 * @param password The new password
-	 * @return true if the new password is valid against the history
-	 */
-	public boolean checkCredentialHistory(Identity identity, String password) {
-		boolean ok = true;
-		int historyLength = loginModule.getPasswordHistory();
-		if(historyLength > 0 && 
-				(!ldapLoginModule.isLDAPEnabled()
-						|| !authenticationDao.hasAuthentication(identity, LDAPAuthenticationController.PROVIDER_LDAP))) {
-			ok = securityManager.checkCredentialHistory(identity, BaseSecurityModule.getDefaultAuthProviderIdentifier(), password);
-		}
-		return ok;
-	}
-	
 }
diff --git a/src/main/java/org/olat/login/auth/OLATAuthentcationForm.java b/src/main/java/org/olat/login/auth/OLATAuthentcationForm.java
index 66fecc136f33838179b9adebf9f3586afceccdf7..73f7d3742a39c5f3c55bd00c0f5e812cee7cc6a0 100644
--- a/src/main/java/org/olat/login/auth/OLATAuthentcationForm.java
+++ b/src/main/java/org/olat/login/auth/OLATAuthentcationForm.java
@@ -58,7 +58,7 @@ public class OLATAuthentcationForm extends FormBasicController {
 
 	
 	/**
-	 * @see org.olat.core.gui.components.Form#validate(org.olat.core.gui.UserRequest)
+	 * @see org.olat.core.gui.components.Form#validate(org.olat.core.gui.UserRequest, Identity)
 	 */
 	@Override
 	public boolean validateFormLogic(UserRequest ureq) {
diff --git a/src/main/java/org/olat/login/oauth/ui/OAuthRegistrationController.java b/src/main/java/org/olat/login/oauth/ui/OAuthRegistrationController.java
index 7ec37f240c8c17758ad9a9975ee9d3f352021e4e..19e96851e51f0ee8d14404897c1174812f82dbca 100644
--- a/src/main/java/org/olat/login/oauth/ui/OAuthRegistrationController.java
+++ b/src/main/java/org/olat/login/oauth/ui/OAuthRegistrationController.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.olat.admin.user.delete.service.UserDeletionManager;
+import org.olat.admin.user.imp.TransientIdentity;
 import org.olat.basesecurity.AuthHelper;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.OrganisationRoles;
@@ -46,13 +47,16 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.login.auth.OLATAuthManager;
 import org.olat.login.oauth.model.OAuthRegistration;
 import org.olat.login.oauth.model.OAuthUser;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
 import org.olat.registration.DisclaimerController;
 import org.olat.registration.RegistrationForm2;
 import org.olat.registration.RegistrationManager;
+import org.olat.user.ChangePasswordForm;
 import org.olat.user.UserManager;
-import org.olat.user.UserModule;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -68,6 +72,7 @@ public class OAuthRegistrationController extends FormBasicController {
 	
 	private final OAuthRegistration registration;
 	private final List<UserPropertyHandler> userPropertyHandlers;
+	private final SyntaxValidator usernameSyntaxValidator;
 
 	private TextElement usernameEl;
 	private SingleSelection langEl;
@@ -77,13 +82,13 @@ public class OAuthRegistrationController extends FormBasicController {
 	
 	private Identity authenticatedIdentity;
 	
-	@Autowired
-	private UserModule userModule;
 	@Autowired
 	private UserManager userManager;
 	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
+	private OLATAuthManager olatAuthManager;
+	@Autowired
 	private UserDeletionManager userDeletionManager;
 	@Autowired
 	private OrganisationService organisationService;
@@ -94,7 +99,9 @@ public class OAuthRegistrationController extends FormBasicController {
 		super(ureq, wControl);
 		setTranslator(Util.createPackageTranslator(RegistrationForm2.class, getLocale(), getTranslator()));
 		setTranslator(Util.createPackageTranslator(UserPropertyHandler.class, getLocale(), getTranslator()));
+		setTranslator(Util.createPackageTranslator(ChangePasswordForm.class, ureq.getLocale(), getTranslator()));
 		userPropertyHandlers = userManager.getUserPropertyHandlersFor(USERPROPERTIES_FORM_IDENTIFIER, false);
+		this.usernameSyntaxValidator = olatAuthManager.createUsernameSytaxValidator();
 		
 		this.registration = registration;
 
@@ -180,18 +187,23 @@ public class OAuthRegistrationController extends FormBasicController {
 			}
 		}
 		
-		String login = usernameEl.getValue();
+		String username = usernameEl.getValue();
+		TransientIdentity newIdentity = new TransientIdentity();
+		newIdentity.setName(username);
+		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
+			FormItem propertyItem = flc.getFormComponent(userPropertyHandler.getName());
+			newIdentity.setProperty(userPropertyHandler.getName(), userPropertyHandler.getStringValue(propertyItem));
+		}
+		
 		usernameEl.clearError();
-		if (!userManager.syntaxCheckOlatLogin(login)) {
-			usernameEl.setErrorKey("form.check3", null);
-			allOk &= false;
-		} else if (userModule.isLoginOnBlacklist(login)) {
-			usernameEl.setErrorKey("form.check6", null);
+		if (!StringHelper.containsNonWhitespace(username)) {
+			usernameEl.setErrorKey("form.legende.mandatory", null);
 			allOk &= false;
 		} else {
-			Identity s = securityManager.findIdentityByName(login);
-			if (s != null) {
-				usernameEl.setErrorKey("form.check6", null);
+			ValidationResult validationResult = usernameSyntaxValidator.validate(username, newIdentity);
+			if (!validationResult.isValid()) {
+				String descriptions = validationResult.getInvalidDescriptions().get(0).getText(getLocale());
+				usernameEl.setErrorKey("error.username.invalid", new String[] { descriptions });
 				allOk &= false;
 			}
 		}
diff --git a/src/main/java/org/olat/login/ui/LoginUIFactory.java b/src/main/java/org/olat/login/ui/LoginUIFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..15c57a41844f23e655de6573261c562e8a1bdf6d
--- /dev/null
+++ b/src/main/java/org/olat/login/ui/LoginUIFactory.java
@@ -0,0 +1,65 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.ui;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collectors;
+
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.util.StringHelper;
+import org.olat.login.validation.ValidationDescription;
+
+/**
+ * 
+ * Initial date: 14 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class LoginUIFactory {
+	
+	public static String formatDescriptionAsList(List<ValidationDescription> descriptions, Locale locale) {
+		return descriptions.stream()
+				.map(d -> "<br/>  - " + d.getText(locale))
+				.collect(Collectors.joining());
+	}
+	
+	static boolean validateInteger(TextElement el, int min) {
+		boolean allOk = true;
+		el.clearError();
+		String val = el.getValue();
+		if(StringHelper.containsNonWhitespace(val)) {
+			try {
+				double value = Integer.parseInt(val);
+				if(min > value) {
+					el.setErrorKey("error.wrong.int", null);
+					allOk = false;
+				}
+			} catch (NumberFormatException e) {
+				el.setErrorKey("error.wrong.int", null);
+				allOk = false;
+			}
+		} else {
+			el.setErrorKey("error.wrong.int", null);
+			allOk = false;
+		}
+		return allOk;
+	}
+}
diff --git a/src/main/java/org/olat/login/ui/PasswordAdminController.java b/src/main/java/org/olat/login/ui/PasswordAdminController.java
new file mode 100644
index 0000000000000000000000000000000000000000..88427b5d8808db2ddb7c91de3ed29d32f52d6962
--- /dev/null
+++ b/src/main/java/org/olat/login/ui/PasswordAdminController.java
@@ -0,0 +1,133 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.ui;
+
+import java.util.List;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.segmentedview.SegmentViewComponent;
+import org.olat.core.gui.components.segmentedview.SegmentViewEvent;
+import org.olat.core.gui.components.segmentedview.SegmentViewFactory;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.util.Util;
+import org.olat.core.util.resource.OresHelper;
+import org.olat.login.LoginModule;
+
+/**
+ * 
+ * Initial date: 14 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class PasswordAdminController extends BasicController implements Activateable2 {
+
+	private static final String SYNTAX_RES_TYPE = "syntax";
+	private static final String POLICY_RES_TYPE = "policy";
+	
+	private VelocityContainer mainVC;
+	private final Link syntaxLink;
+	private final Link policyLink;
+	private final SegmentViewComponent segmentView;
+	
+	private PasswordSyntaxController syntaxCtrl;
+	private PasswordPolicyController policyCtrl;
+	
+	public PasswordAdminController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		setTranslator(Util.createPackageTranslator(LoginModule.class, ureq.getLocale(), getTranslator()));
+		
+		mainVC = createVelocityContainer("admin");
+		
+		segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this);
+		syntaxLink = LinkFactory.createLink("admin.password.syntax", mainVC, this);
+		segmentView.addSegment(syntaxLink, true);
+		policyLink = LinkFactory.createLink("admin.password.policy", mainVC, this);
+		segmentView.addSegment(policyLink, false);
+
+		doOpenSyntax(ureq);
+		putInitialPanel(mainVC);
+	}
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		if(entries == null || entries.isEmpty()) return;
+		
+		String type = entries.get(0).getOLATResourceable().getResourceableTypeName();
+		if(SYNTAX_RES_TYPE.equalsIgnoreCase(type)) {
+			doOpenSyntax(ureq);
+			segmentView.select(syntaxLink);
+		} else if(POLICY_RES_TYPE.equalsIgnoreCase(type)) {
+			doOpenPolicy(ureq);
+			segmentView.select(policyLink);
+		}
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		if(source == segmentView) {
+			if(event instanceof SegmentViewEvent) {
+				SegmentViewEvent sve = (SegmentViewEvent)event;
+				String segmentCName = sve.getComponentName();
+				Component clickedLink = mainVC.getComponent(segmentCName);
+				if (clickedLink == syntaxLink) {
+					doOpenSyntax(ureq);
+				} else if (clickedLink == policyLink) {
+					doOpenPolicy(ureq);
+				}
+			}
+		}
+	}
+	
+	private void doOpenSyntax(UserRequest ureq) {
+		if(syntaxCtrl == null) {
+			WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType(SYNTAX_RES_TYPE), null);
+			syntaxCtrl = new PasswordSyntaxController(ureq, swControl);
+			listenTo(syntaxCtrl);
+		} else {
+			addToHistory(ureq, syntaxCtrl);
+		}
+		mainVC.put("segmentCmp", syntaxCtrl.getInitialComponent());
+	}
+	
+	private void doOpenPolicy(UserRequest ureq) {
+		if(policyCtrl == null) {
+			WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType(POLICY_RES_TYPE), null);
+			policyCtrl = new PasswordPolicyController(ureq, swControl);
+			listenTo(policyCtrl);
+		} else {
+			addToHistory(ureq, policyCtrl);
+		}
+		mainVC.put("segmentCmp", policyCtrl.getInitialComponent());
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+}
diff --git a/src/main/java/org/olat/login/ui/PasswordPolicyController.java b/src/main/java/org/olat/login/ui/PasswordPolicyController.java
index 04fd0366b6bdbfe2ea5318c8c1e72737095c8713..5cd66f09ee159a42d8be759f0a2939062bded663 100644
--- a/src/main/java/org/olat/login/ui/PasswordPolicyController.java
+++ b/src/main/java/org/olat/login/ui/PasswordPolicyController.java
@@ -19,11 +19,12 @@
  */
 package org.olat.login.ui;
 
+import static org.olat.login.ui.LoginUIFactory.validateInteger;
+
 import org.olat.basesecurity.OrganisationRoles;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
-import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
@@ -44,7 +45,6 @@ public class PasswordPolicyController extends FormBasicController {
 	
 	private static final String[] onKeys = new String[] { "on" };
 	
-	private SingleSelection historyEl;
 	private MultipleSelectionElement changeOnceEl;
 	
 	private TextElement validUntilGuiEl;
@@ -76,7 +76,6 @@ public class PasswordPolicyController extends FormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		
-		setFormTitle("password.policy.title");
 		setFormDescription("max.age.description");
 		
 		validUntilGuiEl = uifactory.addTextElement("password.change.valid.until.gui", 20, loginModule.getValidUntilHoursGui().toString(), formLayout);
@@ -89,22 +88,6 @@ public class PasswordPolicyController extends FormBasicController {
 		if(loginModule.isPasswordChangeOnce()) {
 			changeOnceEl.select(onKeys[0], true);
 		}
-		
-		String selectedVal = Integer.toString(loginModule.getPasswordHistory());
-		boolean hasVal = false;
-		String[] historyKeys = new String[] { "0", "1", "2", "5", "10", "15" };
-		for(String historyKey:historyKeys) {
-			if(selectedVal.equals(historyKey)) {
-				hasVal = true;
-			}
-		}
-		String[] historyValues = new String[] { translate("disable.history"), translate("password.after","1"), translate("password.after","2"), translate("password.after","5"), translate("password.after","10"), translate("password.after","15")};
-		if(!hasVal) {
-			historyKeys = append(historyKeys, selectedVal);
-			historyValues = append(historyValues, selectedVal);
-		}
-		historyEl = uifactory.addDropdownSingleselect("password.history", "password.history", formLayout, historyKeys, historyValues, null);
-		historyEl.select(selectedVal, true);
 
 		String maxAge = toMaxAgeAsString(loginModule.getPasswordMaxAge());
 		maxAgeEl = uifactory.addTextElement("max.age", "max.age", 5, maxAge, formLayout);
@@ -154,13 +137,6 @@ public class PasswordPolicyController extends FormBasicController {
 		uifactory.addFormSubmitButton("save", buttonsCont);
 	}
 	
-	private String[] append(String[] array, String val) {
-		String[] newArray = new String[array.length + 1];
-		System.arraycopy(array, 0, newArray, 0, array.length);
-		newArray[array.length] = val;
-		return newArray;
-	}
-	
 	private String toMaxAgeAsString(int maxAge) {
 		if(maxAge < 0) {
 			return "";
@@ -197,37 +173,9 @@ public class PasswordPolicyController extends FormBasicController {
 		allOk &= validateMaxAgeEl(maxAgeAdministratorEl);
 		allOk &= validateMaxAgeEl(maxAgeSysAdminEl);
 		
-		historyEl.clearError();
-		if(!historyEl.isOneSelected()) {
-			historyEl.setErrorKey("form.legende.mandatory", null);
-			allOk &= false;
-		}
-		
 		return allOk;
 	}
 	
-	private boolean validateInteger(TextElement el, int min) {
-		boolean allOk = true;
-		el.clearError();
-		String val = el.getValue();
-		if(StringHelper.containsNonWhitespace(val)) {	
-			try {
-				double value = Integer.parseInt(val);
-				if(min > value) {
-					el.setErrorKey("error.wrong.int", null);
-					allOk = false;
-				}
-			} catch (NumberFormatException e) {
-				el.setErrorKey("error.wrong.int", null);
-				allOk = false;
-			}
-		} else {
-			el.setErrorKey("error.wrong.int", null);
-			allOk = false;
-		}
-		return allOk;	
-	}
-	
 	private boolean validateMaxAgeEl(TextElement el) {
 		boolean allOk = true;
 		
@@ -245,9 +193,6 @@ public class PasswordPolicyController extends FormBasicController {
 	protected void formOK(UserRequest ureq) {
 		loginModule.setPasswordChangeOnce(changeOnceEl.isAtLeastSelected(1));
 		
-		int history = Integer.parseInt(historyEl.getSelectedKey());
-		loginModule.setPasswordHistory(history);
-		
 		Integer validUntilHoursGui = Integer.parseInt(validUntilGuiEl.getValue());
 		loginModule.setValidUntilHoursGui(validUntilHoursGui);
 		Integer validUntilHoursRest = Integer.parseInt(validUntilRestEl.getValue());
diff --git a/src/main/java/org/olat/login/ui/PasswordPreviewController.java b/src/main/java/org/olat/login/ui/PasswordPreviewController.java
new file mode 100644
index 0000000000000000000000000000000000000000..323c14112cc8a11cb58aeffd410bd0aee07c27d8
--- /dev/null
+++ b/src/main/java/org/olat/login/ui/PasswordPreviewController.java
@@ -0,0 +1,106 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.ui;
+
+import static org.olat.login.ui.LoginUIFactory.formatDescriptionAsList;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.Util;
+import org.olat.login.LoginModule;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
+import org.olat.user.ChangePasswordForm;
+
+/**
+ * 
+ * Initial date: 20 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class PasswordPreviewController extends FormBasicController {
+
+	private TextElement passwordEl;
+	private FormLink closeLink;
+
+	private final SyntaxValidator syntaxValidator;
+
+	protected PasswordPreviewController(UserRequest ureq, WindowControl wControl, SyntaxValidator syntaxValidator) {
+		super(ureq, wControl);
+		this.syntaxValidator = syntaxValidator;
+		setTranslator(Util.createPackageTranslator(LoginModule.class, ureq.getLocale(), getTranslator()));
+		setTranslator(Util.createPackageTranslator(ChangePasswordForm.class, ureq.getLocale(), getTranslator()));
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		String descriptions = formatDescriptionAsList(syntaxValidator.getAllDescriptions(), getLocale());
+		setFormDescription("admin.syntax.preview.description", new String[] { descriptions });
+		
+		passwordEl = uifactory.addPasswordElement("admin.syntax.preview.password", "admin.syntax.preview.password", 10000, "", formLayout);
+		passwordEl.setAutocomplete("new-password");
+		
+		FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		formLayout.add(buttonsCont);
+		uifactory.addFormSubmitButton("admin.syntax.preview.validate", buttonsCont);
+		closeLink = uifactory.addFormLink("close", buttonsCont, Link.BUTTON);
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if (source == closeLink) {
+			fireEvent(ureq, FormEvent.DONE_EVENT);
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+	
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		passwordEl.clearError();
+		String newPassword = passwordEl.getValue();
+		ValidationResult validationResult = syntaxValidator.validate(newPassword, getIdentity());
+		if (!validationResult.isValid()) {
+			String descriptions = formatDescriptionAsList(validationResult.getInvalidDescriptions(), getLocale());
+			passwordEl.setErrorKey("error.password.invalid", new String[] { descriptions });
+		}
+		return super.validateFormLogic(ureq);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		// Nothing to do. It is only important to validate the password.
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+}
diff --git a/src/main/java/org/olat/login/ui/PasswordSyntaxController.java b/src/main/java/org/olat/login/ui/PasswordSyntaxController.java
new file mode 100644
index 0000000000000000000000000000000000000000..213270614c19ffb093c85ffc10b2f385d9a3cd66
--- /dev/null
+++ b/src/main/java/org/olat/login/ui/PasswordSyntaxController.java
@@ -0,0 +1,386 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.ui;
+
+import static org.olat.core.gui.components.util.KeyValues.entry;
+import static org.olat.login.LoginModule.AT_LEAST_1;
+import static org.olat.login.LoginModule.AT_LEAST_2;
+import static org.olat.login.LoginModule.AT_LEAST_3;
+import static org.olat.login.LoginModule.DISABLED;
+import static org.olat.login.LoginModule.FORBIDDEN;
+import static org.olat.login.LoginModule.VALIDATE_SEPARATELY;
+import static org.olat.login.ui.LoginUIFactory.validateInteger;
+
+import java.util.Collection;
+
+import org.apache.logging.log4j.Logger;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
+import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.util.KeyValues;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.Util;
+import org.olat.login.LoginModule;
+import org.olat.login.validation.PasswordValidationConfig;
+import org.olat.login.validation.PasswordValidationRulesFactory;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationRulesProvider;
+import org.olat.login.validation.PasswordValidationConfig.Builder;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 14 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class PasswordSyntaxController extends FormBasicController {
+
+	private static final Logger log = Tracing.createLoggerFor(PasswordSyntaxController.class);
+	
+	private static final String FORBIDDEN_USERNAME = "username";
+	private static final String FORBIDDEN_FIRSTNAME = "firstname";
+	private static final String FORBIDDEN_LASTNAME = "lastname";
+
+	private TextElement minLengthEl;
+	private TextElement maxLengthEl;
+	private SingleSelection lettersEl;
+	private SingleSelection lettersUppercaseEl;
+	private SingleSelection lettersLowercaseEl;
+	private SingleSelection digitsAndSpecialsEl;
+	private SingleSelection digitsEl;
+	private SingleSelection specialsEl;
+	private MultipleSelectionElement forbiddenValuesEl;
+	private SingleSelection historyEl;
+	private FormLink previewLink;
+	
+	private CloseableModalController cmc;
+	private PasswordPreviewController previewCtrl;
+	
+	@Autowired
+	private LoginModule loginModule;
+	@Autowired
+	private PasswordValidationRulesFactory passwordValidationRulesFactory;
+
+	public PasswordSyntaxController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		setTranslator(Util.createPackageTranslator(LoginModule.class, ureq.getLocale(), getTranslator()));
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		minLengthEl = uifactory.addTextElement("admin.syntax.min.length", 10,
+				String.valueOf(loginModule.getPasswordMinLength()), formLayout);
+		minLengthEl.setMandatory(true);
+
+		maxLengthEl = uifactory.addTextElement("admin.syntax.max.length", 10,
+				String.valueOf(loginModule.getPasswordMaxLength()), formLayout);
+		maxLengthEl.setMandatory(true);
+		
+		KeyValues lettersKV = new KeyValues();
+		lettersKV.add(entry(DISABLED, translate("admin.syntax.permitted")));
+		lettersKV.add(entry(AT_LEAST_1, translate("admin.syntax.min.1")));
+		lettersKV.add(entry(AT_LEAST_2, translate("admin.syntax.min.2")));
+		lettersKV.add(entry(AT_LEAST_3, translate("admin.syntax.min.3")));
+		lettersKV.add(entry(FORBIDDEN, translate("admin.syntax.forbidden")));
+		lettersKV.add(entry(VALIDATE_SEPARATELY, translate("admin.syntax.letters.lower.upper")));
+		lettersEl = uifactory.addDropdownSingleselect("admin.syntax.letters", formLayout, lettersKV.keys(),
+				lettersKV.values());
+		lettersEl.select(loginModule.getPasswordLetters(), true);
+		lettersEl.addActionListener(FormEvent.ONCHANGE);
+		
+		KeyValues lettersUppercaseKV = new KeyValues();
+		lettersUppercaseKV.add(entry(DISABLED, translate("admin.syntax.permitted")));
+		lettersUppercaseKV.add(entry(AT_LEAST_1, translate("admin.syntax.min.1")));
+		lettersUppercaseKV.add(entry(AT_LEAST_2, translate("admin.syntax.min.2")));
+		lettersUppercaseKV.add(entry(AT_LEAST_3, translate("admin.syntax.min.3")));
+		lettersUppercaseKV.add(entry(FORBIDDEN, translate("admin.syntax.forbidden")));
+		lettersUppercaseEl = uifactory.addDropdownSingleselect("admin.syntax.letters.uppercase", formLayout,
+				lettersUppercaseKV.keys(), lettersUppercaseKV.values());
+		lettersUppercaseEl.select(loginModule.getPasswordLettersUppercase(), true);
+		
+		KeyValues lettersLowercaseKV = new KeyValues();
+		lettersLowercaseKV.add(entry(DISABLED, translate("admin.syntax.permitted")));
+		lettersLowercaseKV.add(entry(AT_LEAST_1, translate("admin.syntax.min.1")));
+		lettersLowercaseKV.add(entry(AT_LEAST_2, translate("admin.syntax.min.2")));
+		lettersLowercaseKV.add(entry(AT_LEAST_3, translate("admin.syntax.min.3")));
+		lettersLowercaseKV.add(entry(FORBIDDEN, translate("admin.syntax.forbidden")));
+		lettersLowercaseEl = uifactory.addDropdownSingleselect("admin.syntax.letters.lowercase", formLayout,
+				lettersLowercaseKV.keys(), lettersLowercaseKV.values());
+		lettersLowercaseEl.select(loginModule.getPasswordLettersLowercase(), true);
+		
+		KeyValues digitsOrSpecialsKV = new KeyValues();
+		digitsOrSpecialsKV.add(entry(DISABLED, translate("admin.syntax.permitted")));
+		digitsOrSpecialsKV.add(entry(AT_LEAST_1, translate("admin.syntax.min.1")));
+		digitsOrSpecialsKV.add(entry(AT_LEAST_2, translate("admin.syntax.min.2")));
+		digitsOrSpecialsKV.add(entry(AT_LEAST_3, translate("admin.syntax.min.3")));
+		digitsOrSpecialsKV.add(entry(FORBIDDEN, translate("admin.syntax.forbidden")));
+		digitsOrSpecialsKV.add(entry(VALIDATE_SEPARATELY, translate("admin.syntax.digits.or.specials")));
+		digitsAndSpecialsEl = uifactory.addDropdownSingleselect("admin.syntax.digits.specials", formLayout, digitsOrSpecialsKV.keys(),
+				digitsOrSpecialsKV.values());
+		digitsAndSpecialsEl.select(loginModule.getPasswordDigitsAndSpecialSigns(), true);
+		digitsAndSpecialsEl.addActionListener(FormEvent.ONCHANGE);
+		
+		KeyValues digitsKV = new KeyValues();
+		digitsKV.add(entry(DISABLED, translate("admin.syntax.permitted")));
+		digitsKV.add(entry(AT_LEAST_1, translate("admin.syntax.min.1")));
+		digitsKV.add(entry(AT_LEAST_2, translate("admin.syntax.min.2")));
+		digitsKV.add(entry(AT_LEAST_3, translate("admin.syntax.min.3")));
+		digitsKV.add(entry(FORBIDDEN, translate("admin.syntax.forbidden")));
+		digitsEl = uifactory.addDropdownSingleselect("admin.syntax.digits", formLayout, digitsKV.keys(),
+				digitsKV.values());
+		digitsEl.select(loginModule.getPasswordDigits(), true);
+		
+		KeyValues specialsKV = new KeyValues();
+		specialsKV.add(entry(DISABLED, translate("admin.syntax.permitted")));
+		specialsKV.add(entry(AT_LEAST_1, translate("admin.syntax.min.1")));
+		specialsKV.add(entry(AT_LEAST_2, translate("admin.syntax.min.2")));
+		specialsKV.add(entry(AT_LEAST_3, translate("admin.syntax.min.3")));
+		specialsKV.add(entry(FORBIDDEN, translate("admin.syntax.forbidden")));
+		specialsEl = uifactory.addDropdownSingleselect("admin.syntax.specials", formLayout, specialsKV.keys(),
+				specialsKV.values());
+		specialsEl.select(loginModule.getPasswordSpecialSigns(), true);
+		
+		KeyValues forbiddenValuesKV = new KeyValues();
+		forbiddenValuesKV.add(entry(FORBIDDEN_USERNAME, translate("admin.syntax.forbidden.username")));
+		forbiddenValuesKV.add(entry(FORBIDDEN_FIRSTNAME, translate("admin.syntax.forbidden.firstname")));
+		forbiddenValuesKV.add(entry(FORBIDDEN_LASTNAME, translate("admin.syntax.forbidden.lastname")));
+		forbiddenValuesEl = uifactory.addCheckboxesVertical("admin.syntax.forbidden.values", formLayout,
+				forbiddenValuesKV.keys(), forbiddenValuesKV.values(), 1);
+		forbiddenValuesEl.select(FORBIDDEN_USERNAME, loginModule.isPasswordUsernameForbidden());
+		forbiddenValuesEl.select(FORBIDDEN_FIRSTNAME, loginModule.isPasswordFirstnameForbidden());
+		forbiddenValuesEl.select(FORBIDDEN_LASTNAME, loginModule.isPasswordLastnameForbidden());
+		
+		String selectedVal = Integer.toString(loginModule.getPasswordHistory());
+		boolean hasVal = false;
+		String[] historyKeys = new String[] { "0", "1", "2", "5", "10", "15" };
+		for(String historyKey:historyKeys) {
+			if(selectedVal.equals(historyKey)) {
+				hasVal = true;
+			}
+		}
+		String[] historyValues = new String[] { translate("disable.history"), translate("password.after","1"), translate("password.after","2"), translate("password.after","5"), translate("password.after","10"), translate("password.after","15")};
+		if(!hasVal) {
+			historyKeys = append(historyKeys, selectedVal);
+			historyValues = append(historyValues, selectedVal);
+		}
+		historyEl = uifactory.addDropdownSingleselect("password.history", "password.history", formLayout, historyKeys, historyValues, null);
+		historyEl.select(selectedVal, true);
+		
+		updateLettersUI();
+		updateDigitsSpecialsUI();
+		
+		FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		formLayout.add(buttonsCont);
+		uifactory.addFormSubmitButton("save", buttonsCont);
+		previewLink = uifactory.addFormLink("admin.syntax.preview", buttonsCont, Link.BUTTON);
+		previewLink.setIconLeftCSS("o_icon o_icon_preview");
+		previewLink.getComponent().setSuppressDirtyFormWarning(true);
+	}
+	
+	private String[] append(String[] array, String val) {
+		String[] newArray = new String[array.length + 1];
+		System.arraycopy(array, 0, newArray, 0, array.length);
+		newArray[array.length] = val;
+		return newArray;
+	}
+
+	@Override
+	protected void propagateDirtinessToContainer(FormItem fiSrc, FormEvent fe) {
+		if (fiSrc != this.previewLink) {
+			super.propagateDirtinessToContainer(fiSrc, fe);
+		}
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if (source == lettersEl) {
+			updateLettersUI();
+		} else if (source == digitsAndSpecialsEl) {
+			updateDigitsSpecialsUI();
+		} else if (source == previewLink) {
+			doOpenPreview(ureq);
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
+	private void updateLettersUI() {
+		boolean validateSeparately = lettersEl.isOneSelected() && VALIDATE_SEPARATELY.equals(lettersEl.getSelectedKey());
+		lettersUppercaseEl.setVisible(validateSeparately);
+		lettersLowercaseEl.setVisible(validateSeparately);
+	}
+
+	private void updateDigitsSpecialsUI() {
+		boolean validateSeparately = digitsAndSpecialsEl.isOneSelected()
+				&& VALIDATE_SEPARATELY.equals(digitsAndSpecialsEl.getSelectedKey());
+		digitsEl.setVisible(validateSeparately);
+		specialsEl.setVisible(validateSeparately);
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		 if (source == previewCtrl) {
+			cmc.deactivate();
+			cleanUp();
+		} else if (source == cmc) {
+			cleanUp();
+		}
+		super.event(ureq, source, event);
+	}
+
+	private void cleanUp() {
+		removeAsListenerAndDispose(previewCtrl);
+		removeAsListenerAndDispose(cmc);
+		previewCtrl = null;
+		cmc = null;
+	}
+
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = super.validateFormLogic(ureq);
+		allOk &= validateInteger(minLengthEl, 1);
+		allOk &= validateInteger(maxLengthEl, 1);
+		if (allOk) {
+			int min = Integer.parseInt(minLengthEl.getValue());
+			int max = Integer.parseInt(maxLengthEl.getValue());
+			if (max < min) {
+				maxLengthEl.setErrorKey("error.password.length.lower", null);
+				allOk = false;
+			}
+		}
+		
+		historyEl.clearError();
+		if(!historyEl.isOneSelected()) {
+			historyEl.setErrorKey("form.legende.mandatory", null);
+			allOk &= false;
+		}
+		
+		return allOk;
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		PasswordValidationConfig config = getPasswordValidationConfig();
+		loginModule.setPasswordMinLength(config.getPasswordMinLength());
+		loginModule.setPasswordMaxLength(config.getPasswordMaxLength());
+		loginModule.setPasswordLetters(config.getPasswordLetters());
+		loginModule.setPasswordLettersUppercase(config.getPasswordLettersUppercase());
+		loginModule.setPasswordLettersLowercase(config.getPasswordLettersLowercase());
+		loginModule.setPasswordDigitsAndSpecialSigns(config.getPasswordDigitsAndSpecialSigns());
+		loginModule.setPasswordDigits(config.getPasswordDigits());
+		loginModule.setPasswordSpecialSigns(config.getPasswordSpecialSigns());
+		loginModule.setPasswordUsernameForbidden(config.isPasswordUsernameForbidden());
+		loginModule.setPasswordFirstnameForbidden(config.isPasswordFirstnameForbidden());
+		loginModule.setPasswordLastnameForbidden(config.isPasswordLastnameForbidden());
+		loginModule.setPasswordHistory(config.getPasswordHistory());
+		
+		log.info("Passwort syntax validation configuration changed by " + getIdentity());
+	}
+	
+	private PasswordValidationConfig getPasswordValidationConfig() {
+		Builder builder = PasswordValidationConfig.builder();
+		
+		int passwordMinLength = Integer.parseInt(minLengthEl.getValue());
+		builder.withPasswordMinLength(passwordMinLength);
+
+		int passwordMaxLength = Integer.parseInt(maxLengthEl.getValue());
+		builder.withPasswordMaxLength(passwordMaxLength);
+		
+		String passwordLetters = lettersEl.isOneSelected()
+				? lettersEl.getSelectedKey()
+				: DISABLED;
+		builder.withPasswordLetters(passwordLetters);
+		
+		String passwordLettersUppercase = VALIDATE_SEPARATELY.equals(passwordLetters)
+										&& lettersUppercaseEl.isOneSelected()
+				? lettersUppercaseEl.getSelectedKey()
+				: DISABLED;
+		builder.withPasswordLettersUppercase(passwordLettersUppercase);
+		
+		String passwordLettersLowercase = VALIDATE_SEPARATELY.equals(passwordLetters)
+										&& lettersLowercaseEl.isOneSelected()
+				? lettersLowercaseEl.getSelectedKey()
+				: DISABLED;
+		builder.withPasswordLettersLowercase(passwordLettersLowercase);
+		
+		String passwordDigitsAndSpecialSigns = digitsAndSpecialsEl.isOneSelected()
+				? digitsAndSpecialsEl.getSelectedKey()
+				: DISABLED;
+		builder.withPasswordDigitsAndSpecialSigns(passwordDigitsAndSpecialSigns);
+		
+		String passwordDigits = VALIDATE_SEPARATELY.equals(passwordDigitsAndSpecialSigns)
+							&& digitsEl.isOneSelected()
+				? digitsEl.getSelectedKey()
+				: DISABLED;
+		builder.withPasswordDigits(passwordDigits);
+		
+		String passwordSpecialSigns = VALIDATE_SEPARATELY.equalsIgnoreCase(passwordDigitsAndSpecialSigns)
+									&& specialsEl.isOneSelected()
+				? specialsEl.getSelectedKey()
+				: DISABLED;
+		builder.withPasswordSpecialSigns(passwordSpecialSigns);
+		
+		Collection<String> forbiddenValuesKeys = forbiddenValuesEl.getSelectedKeys();
+		builder.withPasswordUsernameForbidden(forbiddenValuesKeys.contains(FORBIDDEN_USERNAME));
+		builder.withPasswordFirstnameForbidden(forbiddenValuesKeys.contains(FORBIDDEN_FIRSTNAME));
+		builder.withPasswordLastnameForbidden(forbiddenValuesKeys.contains(FORBIDDEN_LASTNAME));
+		
+		int history = Integer.parseInt(historyEl.getSelectedKey());
+		builder.withPasswordHistory(history);
+		
+		return builder.build();
+	}
+
+	private void doOpenPreview(UserRequest ureq) {
+		boolean allOk = validateFormLogic(ureq);
+		
+		if (allOk) {
+			PasswordValidationConfig config = getPasswordValidationConfig();
+			ValidationRulesProvider rulesProvider = passwordValidationRulesFactory.createRules(config);
+			SyntaxValidator validator = new SyntaxValidator(rulesProvider, true);
+			previewCtrl = new PasswordPreviewController(ureq, getWindowControl(), validator);
+			listenTo(previewCtrl);
+			
+			cmc = new CloseableModalController(getWindowControl(), translate("close"),
+					previewCtrl.getInitialComponent(), true, translate("admin.syntax.preview.title"));
+			cmc.activate();
+			listenTo(cmc);
+		}
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+}
diff --git a/src/main/java/org/olat/login/ui/_content/admin.html b/src/main/java/org/olat/login/ui/_content/admin.html
new file mode 100644
index 0000000000000000000000000000000000000000..5da6ca9b6520104df5d5d858cdd144db9c980766
--- /dev/null
+++ b/src/main/java/org/olat/login/ui/_content/admin.html
@@ -0,0 +1,7 @@
+<div class="clearfix">
+	$r.render("segments")<br/>
+		
+	#if($r.available("segmentCmp"))
+		$r.render("segmentCmp")
+	#end
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/login/validation/AtLeastCharacterRule.java b/src/main/java/org/olat/login/validation/AtLeastCharacterRule.java
new file mode 100644
index 0000000000000000000000000000000000000000..246d395987aa7ae7d432edab61936b8a798f8fa6
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/AtLeastCharacterRule.java
@@ -0,0 +1,63 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import java.util.function.Predicate;
+
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 13 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+class AtLeastCharacterRule extends DescriptionRule {
+
+	private final Predicate<Character> filter;
+	private final int minCount;
+
+	AtLeastCharacterRule(ValidationDescription description, Predicate<Character> filter, int minCount) {
+		super(description);
+		this.filter = filter;
+		this.minCount = minCount;
+	}
+
+	@Override
+	public boolean validate(String value, Identity identity) {
+		int count = 0;
+		for (int i = 0; i < value.length(); i++) {
+			char character = value.charAt(i);
+			if (filter.test(character)) {
+				count++;
+				if (count >= minCount) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public boolean isIdentityRule() {
+		return false;
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/DescriptionRule.java b/src/main/java/org/olat/login/validation/DescriptionRule.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e8182efdab825d7f1492f5bc0171fdbe2085310
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/DescriptionRule.java
@@ -0,0 +1,41 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+/**
+ * 
+ * Initial date: 19 Jun 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+abstract class DescriptionRule implements ValidationRule {
+
+	private final ValidationDescription description;
+
+	DescriptionRule(ValidationDescription description) {
+		this.description = description;
+	}
+
+	@Override
+	public ValidationDescription getDescription() {
+		return description;
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/HistoryRule.java b/src/main/java/org/olat/login/validation/HistoryRule.java
new file mode 100644
index 0000000000000000000000000000000000000000..247565ed82104d4a02ef52fb1348ff48306e12e5
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/HistoryRule.java
@@ -0,0 +1,73 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import org.olat.basesecurity.BaseSecurity;
+import org.olat.basesecurity.BaseSecurityModule;
+import org.olat.basesecurity.manager.AuthenticationDAO;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.id.Identity;
+import org.olat.ldap.LDAPLoginModule;
+import org.olat.ldap.ui.LDAPAuthenticationController;
+
+/**
+ * 
+ * Initial date: 21 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+class HistoryRule extends DescriptionRule {
+	
+	private int historyLength;
+
+	HistoryRule(ValidationDescription description, int historyLength) {
+		super(description);
+		this.historyLength = historyLength;
+	}
+
+	@Override
+	public boolean validate(String value, Identity identity) {
+		BaseSecurity securityManager = CoreSpringFactory.getImpl(BaseSecurity.class);
+		
+		boolean ok = true;
+		// Is this the right place to check if the user is logged in with LDAP?
+		// What happens if someone changes the password of someone else?
+		// Further, the description is shown even if the user is logged in with LDAP,
+		// although this rule is ignored in that case.
+		if (notAutenticatedWithLDAP(identity)) {
+			ok = securityManager.checkCredentialHistory(identity, BaseSecurityModule.getDefaultAuthProviderIdentifier(),
+					value, historyLength);
+		}
+		return ok;
+	}
+
+	private boolean notAutenticatedWithLDAP(Identity identity) {
+		LDAPLoginModule ldapLoginModule = CoreSpringFactory.getImpl(LDAPLoginModule.class);
+		AuthenticationDAO authenticationDao = CoreSpringFactory.getImpl(AuthenticationDAO.class);
+		return !ldapLoginModule.isLDAPEnabled()
+				|| !authenticationDao.hasAuthentication(identity, LDAPAuthenticationController.PROVIDER_LDAP);
+	}
+
+	@Override
+	public boolean isIdentityRule() {
+		return true;
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/IdentityValueForbiddenRule.java b/src/main/java/org/olat/login/validation/IdentityValueForbiddenRule.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b8fb75861247640c02fdfe6311ca5652e5a3fab
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/IdentityValueForbiddenRule.java
@@ -0,0 +1,57 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import java.util.function.Function;
+
+import org.olat.core.id.Identity;
+import org.olat.core.util.StringHelper;
+
+/**
+ * 
+ * Initial date: 14 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+class IdentityValueForbiddenRule extends DescriptionRule {
+
+	private final Function<Identity, String> forbiddenValue;
+
+	IdentityValueForbiddenRule(ValidationDescription description, Function<Identity, String> forbiddenValue) {
+		super(description);
+		this.forbiddenValue = forbiddenValue;
+	}
+
+	@Override
+	public boolean validate(String value, Identity identity) {
+		if (identity == null) return true;
+		
+		String identityValue = forbiddenValue.apply(identity);
+		if (!StringHelper.containsNonWhitespace(identityValue)) return true;
+		
+		return !value.toLowerCase().contains(identityValue.toLowerCase());
+	}
+
+	@Override
+	public boolean isIdentityRule() {
+		return true;
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/OppositeRule.java b/src/main/java/org/olat/login/validation/OppositeRule.java
new file mode 100644
index 0000000000000000000000000000000000000000..380b7cc40e2138363b5dfbcaabe59988a9ab4e83
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/OppositeRule.java
@@ -0,0 +1,54 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import org.olat.core.id.Identity;
+
+/**
+ * Switches a valid rule to an invalid and an invalid rule to a valid rule.
+ * 
+ * Initial date: 14 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+class OppositeRule implements ValidationRule {
+
+	private final ValidationRule rule;
+	
+	OppositeRule(ValidationRule rule) {
+		this.rule = rule;
+	}
+
+	@Override
+	public boolean validate(String value, Identity identity) {
+		return !rule.validate(value, null);
+	}
+
+	@Override
+	public ValidationDescription getDescription() {
+		return rule.getDescription();
+	}
+
+	@Override
+	public boolean isIdentityRule() {
+		return rule.isIdentityRule();
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/PasswordValidationConfig.java b/src/main/java/org/olat/login/validation/PasswordValidationConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..d65f39283b593558cab360c7d3367df00149cdd7
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/PasswordValidationConfig.java
@@ -0,0 +1,192 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+/**
+ * 
+ * Initial date: 16 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class PasswordValidationConfig {
+
+	private final int passwordMinLength;
+	private final int passwordMaxLength;
+	private final String passwordLetters;
+	private final String passwordLettersUppercase;
+	private final String passwordLettersLowercase;
+	private final String passwordDigitsAndSpecialSigns;
+	private final String passwordDigits;
+	private final String passwordSpecialSigns;
+	private final boolean passwordUsernameForbidden;
+	private final boolean passwordFirstnameForbidden;
+	private final boolean passwordLastnameForbidden;
+	private final int passwordHistory;
+
+	private PasswordValidationConfig(Builder builder) {
+		this.passwordMinLength = builder.passwordMinLength;
+		this.passwordMaxLength = builder.passwordMaxLength;
+		this.passwordLetters = builder.passwordLetters;
+		this.passwordLettersUppercase = builder.passwordLettersUppercase;
+		this.passwordLettersLowercase = builder.passwordLettersLowercase;
+		this.passwordDigitsAndSpecialSigns = builder.passwordDigitsAndSpecialSigns;
+		this.passwordDigits = builder.passwordDigits;
+		this.passwordSpecialSigns = builder.passwordSpecialSigns;
+		this.passwordUsernameForbidden = builder.passwordUsernameForbidden;
+		this.passwordFirstnameForbidden = builder.passwordFirstnameForbidden;
+		this.passwordLastnameForbidden = builder.passwordLastnameForbidden;
+		this.passwordHistory = builder.passwordHistory;
+	}
+	
+	public int getPasswordMinLength() {
+		return passwordMinLength;
+	}
+
+	public int getPasswordMaxLength() {
+		return passwordMaxLength;
+	}
+
+	public String getPasswordLetters() {
+		return passwordLetters;
+	}
+
+	public String getPasswordLettersUppercase() {
+		return passwordLettersUppercase;
+	}
+
+	public String getPasswordLettersLowercase() {
+		return passwordLettersLowercase;
+	}
+
+	public String getPasswordDigitsAndSpecialSigns() {
+		return passwordDigitsAndSpecialSigns;
+	}
+
+	public String getPasswordDigits() {
+		return passwordDigits;
+	}
+
+	public String getPasswordSpecialSigns() {
+		return passwordSpecialSigns;
+	}
+
+	public boolean isPasswordUsernameForbidden() {
+		return passwordUsernameForbidden;
+	}
+
+	public boolean isPasswordFirstnameForbidden() {
+		return passwordFirstnameForbidden;
+	}
+
+	public boolean isPasswordLastnameForbidden() {
+		return passwordLastnameForbidden;
+	}
+
+	public int getPasswordHistory() {
+		return passwordHistory;
+	}
+
+	public static Builder builder() {
+		return new Builder();
+	}
+
+	public static final class Builder {
+		private int passwordMinLength;
+		private int passwordMaxLength;
+		private String passwordLetters;
+		private String passwordLettersUppercase;
+		private String passwordLettersLowercase;
+		private String passwordDigitsAndSpecialSigns;
+		private String passwordDigits;
+		private String passwordSpecialSigns;
+		private boolean passwordUsernameForbidden;
+		private boolean passwordFirstnameForbidden;
+		private boolean passwordLastnameForbidden;
+		private int passwordHistory;
+
+		private Builder() {
+		}
+
+		public Builder withPasswordMinLength(int passwordMinLength) {
+			this.passwordMinLength = passwordMinLength;
+			return this;
+		}
+
+		public Builder withPasswordMaxLength(int passwordMaxLength) {
+			this.passwordMaxLength = passwordMaxLength;
+			return this;
+		}
+
+		public Builder withPasswordLetters(String passwordLetters) {
+			this.passwordLetters = passwordLetters;
+			return this;
+		}
+
+		public Builder withPasswordLettersUppercase(String passwordLettersUppercase) {
+			this.passwordLettersUppercase = passwordLettersUppercase;
+			return this;
+		}
+
+		public Builder withPasswordLettersLowercase(String passwordLettersLowercase) {
+			this.passwordLettersLowercase = passwordLettersLowercase;
+			return this;
+		}
+
+		public Builder withPasswordDigitsAndSpecialSigns(String passwordDigitsAndSpecialSigns) {
+			this.passwordDigitsAndSpecialSigns = passwordDigitsAndSpecialSigns;
+			return this;
+		}
+
+		public Builder withPasswordDigits(String passwordDigits) {
+			this.passwordDigits = passwordDigits;
+			return this;
+		}
+
+		public Builder withPasswordSpecialSigns(String passwordSpecialSigns) {
+			this.passwordSpecialSigns = passwordSpecialSigns;
+			return this;
+		}
+
+		public Builder withPasswordUsernameForbidden(boolean passwordUsernameForbidden) {
+			this.passwordUsernameForbidden = passwordUsernameForbidden;
+			return this;
+		}
+
+		public Builder withPasswordFirstnameForbidden(boolean passwordFirstnameForbidden) {
+			this.passwordFirstnameForbidden = passwordFirstnameForbidden;
+			return this;
+		}
+
+		public Builder withPasswordLastnameForbidden(boolean passwordLastnameForbidden) {
+			this.passwordLastnameForbidden = passwordLastnameForbidden;
+			return this;
+		}
+		
+		public Builder withPasswordHistory(int passwordHistory) {
+			this.passwordHistory = passwordHistory;
+			return this;
+		}
+
+		public PasswordValidationConfig build() {
+			return new PasswordValidationConfig(this);
+		}
+	}
+	
+}
diff --git a/src/main/java/org/olat/login/validation/PasswordValidationRuleFactory.java b/src/main/java/org/olat/login/validation/PasswordValidationRuleFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..0721f1e50a9482ccc12bba8c3d59fb643b4f6ab8
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/PasswordValidationRuleFactory.java
@@ -0,0 +1,192 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import static java.util.regex.Pattern.UNICODE_CHARACTER_CLASS;
+
+import java.util.Locale;
+import java.util.function.Function;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.olat.core.gui.translator.Translator;
+import org.olat.core.id.Identity;
+import org.olat.core.util.Util;
+import org.olat.login.LoginModule;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 12 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class PasswordValidationRuleFactory {
+	
+	public ValidationRule createVisibleCharactersRule(int min, int max) {
+		ValidationDescription description = createDescription("password.rule.length", min, max);
+		Pattern pattern = Pattern.compile("^\\p{Graph}{" + min + "," + max + "}$", UNICODE_CHARACTER_CLASS);
+		return new RegexRule(description, pattern);
+	}
+	
+	public ValidationRule createAtLeastLettersRule(int min) {
+		ValidationDescription description = createDescription("password.rule.at.least.letters", min);
+		return new AtLeastCharacterRule(description, Character::isLetter, min);
+	}
+	
+	public ValidationRule createAtLeastLettersUppercaseRule(int min) {
+		ValidationDescription description = createDescription("password.rule.at.least.letters.uppercase", min);
+		return new AtLeastCharacterRule(description, Character::isUpperCase, min);
+	}
+	
+	public ValidationRule createAtLeastLettersLowercaseRule(int min) {
+		ValidationDescription description = createDescription("password.rule.at.least.letters.lowercase", min);
+		return new AtLeastCharacterRule(description, Character::isLowerCase, min);
+	}
+	
+	public ValidationRule createAtLeastDigitsRule(int min) {
+		ValidationDescription description = createDescription("password.rule.at.least.digits", min);
+		return new AtLeastCharacterRule(description, Character::isDigit, min);
+	}
+	
+	public ValidationRule createAtLeastSpecialSignsRule(int min) {
+		ValidationDescription description = createDescription("password.rule.at.least.specials", min);
+		// at least 2: .*\\W.*\\W.*
+		String regex = Stream.generate(() -> ".*").limit(min + 1).collect(Collectors.joining("\\W"));
+		Pattern pattern = Pattern.compile(regex, UNICODE_CHARACTER_CLASS);
+		return new RegexRule(description, pattern);
+	}
+	
+	public ValidationRule createAtLeastDigitsOrSpecialSignsRule(int min) {
+		ValidationDescription description = createDescription("password.rule.at.least.digits.specials", min);
+		String regex = Stream.generate(() -> ".*").limit(min + 1).collect(Collectors.joining("[\\d|\\W]"));
+		Pattern pattern = Pattern.compile(regex, UNICODE_CHARACTER_CLASS);
+		return new RegexRule(description, pattern);
+	}
+	
+	public ValidationRule createLettersPermittedRule() {
+		ValidationDescription description = createDescription("password.rule.permitted.letters");
+		return new TrueRule(description);
+	}
+	
+	public ValidationRule createLettersUppercasePermittedRule() {
+		ValidationDescription description = createDescription("password.rule.permitted.letters.uppercase");
+		return new TrueRule(description);
+	}
+	
+	public ValidationRule createLettersLowercasePermittedRule() {
+		ValidationDescription description = createDescription("password.rule.permitted.letters.lowercase");
+		return new TrueRule(description);
+	}
+	
+	public ValidationRule createDigitsAndSpecialSignsPermittedRule() {
+		ValidationDescription description = createDescription("password.rule.permitted.digits.specials");
+		return new TrueRule(description);
+	}
+	
+	public ValidationRule createDigitsPermittedRule() {
+		ValidationDescription description = createDescription("password.rule.permitted.digits");
+		return new TrueRule(description);
+	}
+	
+	public ValidationRule createSpecialSignsPermittedRule() {
+		ValidationDescription description = createDescription("password.rule.permitted.specials");
+		return new TrueRule(description);
+	}
+	
+	public ValidationRule createLettersForbiddenRule() {
+		ValidationDescription description = createDescription("password.rule.forbidden.letters");
+		return new OppositeRule(new AtLeastCharacterRule(description, Character::isLetter, 1));
+	}
+	
+	public ValidationRule createLettersUppercaseForbiddenRule() {
+		ValidationDescription description = createDescription("password.rule.forbidden.letters.uppercase");
+		return new OppositeRule(new AtLeastCharacterRule(description, Character::isUpperCase, 1));
+	}
+	
+	public ValidationRule createLettersLowercaseForbiddenRule() {
+		ValidationDescription description = createDescription("password.rule.forbidden.letters.lowercase");
+		return new OppositeRule(new AtLeastCharacterRule(description, Character::isLowerCase, 1));
+	}
+	
+	public ValidationRule createDigitsForbiddenRule() {
+		ValidationDescription description = createDescription("password.rule.forbidden.digits");
+		return new OppositeRule(new AtLeastCharacterRule(description, Character::isDigit, 1));
+	}
+	
+	public ValidationRule createSpecialSignsForbiddenRule() {
+		ValidationDescription description = createDescription("password.rule.forbidden.specials");
+		Pattern pattern = Pattern.compile(".*\\W+.*", UNICODE_CHARACTER_CLASS);
+		return new OppositeRule(new RegexRule(description, pattern));
+	}
+	
+	public ValidationRule createDigitsAndSpecialSignsForbiddenRule() {
+		ValidationDescription description = createDescription("password.rule.forbidden.specials");
+		Pattern pattern = Pattern.compile(".*[\\W|\\d]+.*", UNICODE_CHARACTER_CLASS);
+		return new OppositeRule(new RegexRule(description, pattern));
+	}
+
+	public ValidationRule createUsernameForbiddenRule() {
+		ValidationDescription description = createDescription("password.rule.forbidden.username");
+		Function<Identity, String> forbiddenValue = i -> i.getName();
+		return new IdentityValueForbiddenRule(description, forbiddenValue);
+	}
+
+	public ValidationRule createUserFirstnameForbiddenRule() {
+		ValidationDescription description = createDescription("password.rule.forbidden.user.firstname");
+		Function<Identity, String> forbiddenValue = i -> i.getUser().getFirstName();
+		return new IdentityValueForbiddenRule(description, forbiddenValue);
+	}
+
+	public ValidationRule createUserLastnameForbiddenRule() {
+		ValidationDescription description = createDescription("password.rule.forbidden.user.lastname");
+		Function<Identity, String> forbiddenValue = i -> i.getUser().getLastName();
+		return new IdentityValueForbiddenRule(description, forbiddenValue);
+	}
+
+	public ValidationRule createHistoryRule(int numberChanges) {
+		ValidationDescription description = createDescription("password.rule.history");
+		return new HistoryRule(description, numberChanges);
+	}
+
+	private ValidationDescription createDescription(String i18nKey) {
+		return new TranslatedDescription(createTranslator(), i18nKey);
+	}
+	
+	private ValidationDescription createDescription(String i18nKey, int arg) {
+		return createDescription(i18nKey, new String[] { String.valueOf(arg) } );
+	}
+	
+	private ValidationDescription createDescription(String i18nKey, int arg1, int arg2) {
+		return createDescription(i18nKey, new String[] { String.valueOf(arg1), String.valueOf(arg2) } );
+	}
+	
+	private ValidationDescription createDescription(String i18nKey, String[] args) {
+		return new TranslatedDescription(createTranslator(), i18nKey, args);
+	}
+
+	protected Translator createTranslator() {
+		// The user locale is set later, so use the default locale to construct the translator.
+		return Util.createPackageTranslator(LoginModule.class, Locale.getDefault());
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/PasswordValidationRulesFactory.java b/src/main/java/org/olat/login/validation/PasswordValidationRulesFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..d5e09467ce7b134af0047e59d7bed0492ad9323a
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/PasswordValidationRulesFactory.java
@@ -0,0 +1,178 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import org.olat.login.LoginModule;
+import org.olat.login.validation.PasswordValidationConfig.Builder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 12 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class PasswordValidationRulesFactory {
+
+	@Autowired
+	private PasswordValidationRuleFactory ruleFactory;
+	@Autowired
+	private LoginModule loginModule;
+
+	public ValidationRulesProvider createRules() {
+		Builder configBuilder = PasswordValidationConfig.builder();
+		configBuilder.withPasswordMinLength(loginModule.getPasswordMinLength());
+		configBuilder.withPasswordMaxLength(loginModule.getPasswordMaxLength());
+		configBuilder.withPasswordLetters(loginModule.getPasswordLetters());
+		configBuilder.withPasswordLettersUppercase(loginModule.getPasswordLettersUppercase());
+		configBuilder.withPasswordLettersLowercase(loginModule.getPasswordLettersLowercase());
+		configBuilder.withPasswordDigitsAndSpecialSigns(loginModule.getPasswordDigitsAndSpecialSigns());
+		configBuilder.withPasswordDigits(loginModule.getPasswordDigits());
+		configBuilder.withPasswordSpecialSigns(loginModule.getPasswordSpecialSigns());
+		configBuilder.withPasswordUsernameForbidden(loginModule.isPasswordUsernameForbidden());
+		configBuilder.withPasswordFirstnameForbidden(loginModule.isPasswordFirstnameForbidden());
+		configBuilder.withPasswordLastnameForbidden(loginModule.isPasswordLastnameForbidden());
+		configBuilder.withPasswordHistory(loginModule.getPasswordHistory());
+		return createRules(configBuilder.build());
+	}
+	
+	public ValidationRulesProvider createRules(PasswordValidationConfig config) {
+		ValidationRulesProviderBuilder providerBuilder = new ValidationRulesProviderBuilder();
+		
+		ValidationRule visibleCharactersRule = ruleFactory.createVisibleCharactersRule(config.getPasswordMinLength(),
+				config.getPasswordMaxLength());
+		providerBuilder.add(visibleCharactersRule);
+		
+		if (LoginModule.VALIDATE_SEPARATELY.equals(config.getPasswordLetters())) {
+			ValidationRule lettersUppercaseRule = createLettersUppercaseRule(config.getPasswordLettersUppercase());
+			providerBuilder.add(lettersUppercaseRule);
+			ValidationRule lettersLowercaseRule = createLettersLowercaseRule(config.getPasswordLettersLowercase());
+			providerBuilder.add(lettersLowercaseRule);
+		} else {
+			ValidationRule lettersRule = createLettersRule(config.getPasswordLetters());
+			providerBuilder.add(lettersRule);
+		}
+		
+		if (LoginModule.VALIDATE_SEPARATELY.equals(config.getPasswordDigitsAndSpecialSigns())) {
+			ValidationRule digitsRule = createDigitsRule(config.getPasswordDigits());
+			providerBuilder.add(digitsRule);
+			ValidationRule specialSignsRule = createSpecialSignsRule(config.getPasswordSpecialSigns());
+			providerBuilder.add(specialSignsRule);
+		} else {
+			ValidationRule digitsOrSpecialSignsRule = createDigitsAndSpecialSignsRule(config.getPasswordDigitsAndSpecialSigns());
+			providerBuilder.add(digitsOrSpecialSignsRule);
+		}
+		
+		if (config.isPasswordUsernameForbidden()) {
+			ValidationRule usernameForbiddenRule = ruleFactory.createUsernameForbiddenRule();
+			providerBuilder.add(usernameForbiddenRule);
+		}
+		if (config.isPasswordFirstnameForbidden()) {
+			ValidationRule userFirstnameForbiddenRule = ruleFactory.createUserFirstnameForbiddenRule();
+			providerBuilder.add(userFirstnameForbiddenRule);
+		}
+		if (config.isPasswordLastnameForbidden()) {
+			ValidationRule userLastnameForbiddenRule = ruleFactory.createUserLastnameForbiddenRule();
+			providerBuilder.add(userLastnameForbiddenRule);
+		}
+		
+		if (config.getPasswordHistory() > 0) {
+			ValidationRule historyRule = ruleFactory.createHistoryRule(config.getPasswordHistory());
+			providerBuilder.add(historyRule);
+		}
+		
+		return providerBuilder.create();
+	}
+	
+	private ValidationRule createLettersRule(String passwordLetters) {
+		switch (passwordLetters) {
+		case LoginModule.AT_LEAST_1: return ruleFactory.createAtLeastLettersRule(1);
+		case LoginModule.AT_LEAST_2: return ruleFactory.createAtLeastLettersRule(2);
+		case LoginModule.AT_LEAST_3: return ruleFactory.createAtLeastLettersRule(3);
+		case LoginModule.FORBIDDEN: return ruleFactory.createLettersForbiddenRule();
+		case LoginModule.DISABLED:
+		default:
+			return ruleFactory.createLettersPermittedRule();
+		}
+	}
+	
+	private ValidationRule createLettersUppercaseRule(String passwordLettersUppercase) {
+		switch (passwordLettersUppercase) {
+		case LoginModule.AT_LEAST_1: return ruleFactory.createAtLeastLettersUppercaseRule(1);
+		case LoginModule.AT_LEAST_2: return ruleFactory.createAtLeastLettersUppercaseRule(2);
+		case LoginModule.AT_LEAST_3: return ruleFactory.createAtLeastLettersUppercaseRule(3);
+		case LoginModule.FORBIDDEN: return ruleFactory.createLettersUppercaseForbiddenRule();
+		case LoginModule.DISABLED:
+		default:
+			return ruleFactory.createLettersPermittedRule();
+		}
+	}
+	
+	private ValidationRule createLettersLowercaseRule(String passwordLettersLowercase) {
+		switch (passwordLettersLowercase) {
+		case LoginModule.AT_LEAST_1: return ruleFactory.createAtLeastLettersLowercaseRule(1);
+		case LoginModule.AT_LEAST_2: return ruleFactory.createAtLeastLettersLowercaseRule(2);
+		case LoginModule.AT_LEAST_3: return ruleFactory.createAtLeastLettersLowercaseRule(3);
+		case LoginModule.FORBIDDEN: return ruleFactory.createLettersLowercaseForbiddenRule();
+		case LoginModule.DISABLED:
+		default:
+			return ruleFactory.createLettersPermittedRule();
+		}
+	}
+	
+	private ValidationRule createDigitsAndSpecialSignsRule(String passwordDigitsOrSpecialSigns) {
+		switch (passwordDigitsOrSpecialSigns) {
+		case LoginModule.AT_LEAST_1: return ruleFactory.createAtLeastDigitsOrSpecialSignsRule(1);
+		case LoginModule.AT_LEAST_2: return ruleFactory.createAtLeastDigitsOrSpecialSignsRule(2);
+		case LoginModule.AT_LEAST_3: return ruleFactory.createAtLeastDigitsOrSpecialSignsRule(3);
+		case LoginModule.FORBIDDEN: return ruleFactory.createDigitsAndSpecialSignsForbiddenRule();
+		case LoginModule.DISABLED:
+		default:
+			return ruleFactory.createDigitsAndSpecialSignsPermittedRule();
+		}
+	}
+	
+	private ValidationRule createDigitsRule(String passwordDigits) {
+		switch (passwordDigits) {
+		case LoginModule.AT_LEAST_1: return ruleFactory.createAtLeastDigitsRule(1);
+		case LoginModule.AT_LEAST_2: return ruleFactory.createAtLeastDigitsRule(2);
+		case LoginModule.AT_LEAST_3: return ruleFactory.createAtLeastDigitsRule(3);
+		case LoginModule.FORBIDDEN: return ruleFactory.createDigitsForbiddenRule();
+		case LoginModule.DISABLED:
+		default:
+			return ruleFactory.createDigitsPermittedRule();
+		}
+	}
+	
+	private ValidationRule createSpecialSignsRule(String passwordSpecialSigns) {
+		switch (passwordSpecialSigns) {
+		case LoginModule.AT_LEAST_1: return ruleFactory.createAtLeastSpecialSignsRule(1);
+		case LoginModule.AT_LEAST_2: return ruleFactory.createAtLeastSpecialSignsRule(2);
+		case LoginModule.AT_LEAST_3: return ruleFactory.createAtLeastSpecialSignsRule(3);
+		case LoginModule.FORBIDDEN: return ruleFactory.createSpecialSignsForbiddenRule();
+		case LoginModule.DISABLED:
+		default:
+			return ruleFactory.createSpecialSignsPermittedRule();
+		}
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/RegexRule.java b/src/main/java/org/olat/login/validation/RegexRule.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c9e99437e08439a247c6c15a496426be6aa83f0
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/RegexRule.java
@@ -0,0 +1,55 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import java.util.regex.Pattern;
+
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 13 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+class RegexRule extends DescriptionRule {
+
+	private final Pattern pattern;
+	
+	RegexRule(ValidationDescription description, String pattern) {
+		this(description, Pattern.compile(pattern));
+	}
+	
+	RegexRule(ValidationDescription description, Pattern pattern) {
+		super(description);
+		this.pattern = pattern;
+	}
+
+	@Override
+	public boolean validate(String value, Identity identity) {
+		return pattern.matcher(value).matches();
+	}
+
+	@Override
+	public boolean isIdentityRule() {
+		return false;
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/SyntaxValidator.java b/src/main/java/org/olat/login/validation/SyntaxValidator.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c6e36b09f3844c3649857bce6891be94b0e2561
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/SyntaxValidator.java
@@ -0,0 +1,108 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 12 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class SyntaxValidator {
+
+	private final List<ValidationRule> rules;
+	private final boolean validateAll;
+
+	public SyntaxValidator(ValidationRulesProvider provider, boolean validateAll) {
+		this.rules = provider.getRules();
+		this.validateAll = validateAll;
+	}
+	
+	public List<ValidationDescription> getAllDescriptions() {
+		return getAllDescriptions(false);
+	}
+	
+	public List<ValidationDescription> getAllDescriptions(boolean ignoreIdentityValidations) {
+		return rules.stream()
+				.filter(identityRuleFilter(ignoreIdentityValidations))
+				.map(ValidationRule::getDescription)
+				.collect(Collectors.toList());
+	}
+
+	private Predicate<? super ValidationRule> identityRuleFilter(boolean ignoreIdentityRules) {
+		return rule -> ignoreIdentityRules? !rule.isIdentityRule(): true;
+	}
+
+	public ValidationResult validate(String value) {
+		ValidationResultImpl result = new ValidationResultImpl();
+		for (ValidationRule rule : rules) {
+			if (!rule.isIdentityRule()) {
+				if (!rule.validate(value, null)) {
+					result.addInvalidRule(rule.getDescription());
+					if (!validateAll) {
+						return result;
+					}
+				}
+			}
+		}
+		return result;
+	}
+
+	public ValidationResult validate(String value, Identity identity) {
+		ValidationResultImpl result = new ValidationResultImpl();
+		for (ValidationRule rule : rules) {
+			if (!rule.validate(value, identity)) {
+				result.addInvalidRule(rule.getDescription());
+				if (!validateAll) {
+					return result;
+				}
+			}
+		}
+		return result;
+	}
+	
+	private static class ValidationResultImpl implements ValidationResult {
+		
+		private final List<ValidationDescription> invalidDescription = new ArrayList<>();
+
+		@Override
+		public boolean isValid() {
+			return invalidDescription.isEmpty();
+		}
+
+		@Override
+		public List<ValidationDescription> getInvalidDescriptions() {
+			return invalidDescription;
+		}
+
+		public void addInvalidRule(ValidationDescription description) {
+			invalidDescription.add(description);
+		}
+
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/TranslatedDescription.java b/src/main/java/org/olat/login/validation/TranslatedDescription.java
new file mode 100644
index 0000000000000000000000000000000000000000..b8486fee43f0520ab6899928d9a5bcd0aa106c92
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/TranslatedDescription.java
@@ -0,0 +1,54 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import java.util.Locale;
+
+import org.olat.core.gui.translator.Translator;
+
+/**
+ * 
+ * Initial date: 13 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class TranslatedDescription implements ValidationDescription {
+
+	private final Translator translator;
+	private final String i18nKey;
+	private final String[] args;
+
+	public TranslatedDescription(Translator translator, String i18nKey) {
+		this(translator, i18nKey, null);
+	}
+	
+	public TranslatedDescription(Translator translator, String i18nKey, String[] args) {
+		this.translator = translator;
+		this.i18nKey = i18nKey;
+		this.args = args;
+	}
+
+	@Override
+	public String getText(Locale locale) {
+		translator.setLocale(locale);
+		return translator.translate(i18nKey, args);
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/TrueRule.java b/src/main/java/org/olat/login/validation/TrueRule.java
new file mode 100644
index 0000000000000000000000000000000000000000..58b35b9118c30f41ad4e48f74257d3a72762eb7b
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/TrueRule.java
@@ -0,0 +1,46 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 20 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+class TrueRule extends DescriptionRule {
+
+	public TrueRule(ValidationDescription description) {
+		super(description);
+	}
+
+	@Override
+	public boolean validate(String value, Identity identity) {
+		return true;
+	}
+
+	@Override
+	public boolean isIdentityRule() {
+		return false;
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/UsernameBlackListRule.java b/src/main/java/org/olat/login/validation/UsernameBlackListRule.java
new file mode 100644
index 0000000000000000000000000000000000000000..1d5c6ee29bf73368083eb2fd9bee42aabc4922b1
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/UsernameBlackListRule.java
@@ -0,0 +1,49 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.id.Identity;
+import org.olat.user.UserModule;
+
+/**
+ * 
+ * Initial date: 19 Jun 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+class UsernameBlackListRule extends DescriptionRule {
+
+	UsernameBlackListRule(ValidationDescription description) {
+		super(description);
+	}
+
+	@Override
+	public boolean validate(String value, Identity identity) {
+		UserModule userModule = CoreSpringFactory.getImpl(UserModule.class);
+		return !userModule.isLoginOnBlacklist(value);
+	}
+
+	@Override
+	public boolean isIdentityRule() {
+		return false;
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/UsernameInUseRule.java b/src/main/java/org/olat/login/validation/UsernameInUseRule.java
new file mode 100644
index 0000000000000000000000000000000000000000..cae773901b6670464552813baf3a3a87f5e66519
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/UsernameInUseRule.java
@@ -0,0 +1,49 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import org.olat.basesecurity.BaseSecurity;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 19 Jun 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+class UsernameInUseRule extends DescriptionRule {
+
+	UsernameInUseRule(ValidationDescription description) {
+		super(description);
+	}
+
+	@Override
+	public boolean validate(String value, Identity identity) {
+		BaseSecurity securityManager = CoreSpringFactory.getImpl(BaseSecurity.class);
+		return securityManager.findIdentityByName(value) == null;
+	}
+
+	@Override
+	public boolean isIdentityRule() {
+		return false;
+	}
+
+}
diff --git a/src/main/java/org/olat/login/validation/UsernameValidationRulesFactory.java b/src/main/java/org/olat/login/validation/UsernameValidationRulesFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..78727db8a95d38e1ab4e3660e1beee29096e0313
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/UsernameValidationRulesFactory.java
@@ -0,0 +1,73 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import java.util.Locale;
+
+import org.olat.core.gui.translator.Translator;
+import org.olat.core.util.Util;
+import org.olat.login.LoginModule;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 19 Jun 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class UsernameValidationRulesFactory {
+
+	@Autowired
+	private LoginModule loginModule;
+	
+	public ValidationRulesProvider createRules() {
+		ValidationRulesProviderBuilder providerBuilder = new ValidationRulesProviderBuilder();
+		providerBuilder.add(createUsernameSyntaxRule());
+		providerBuilder.add(createBlackListRule());
+		providerBuilder.add(createUsernameExistsRule());
+		return providerBuilder.create();
+	}
+
+	protected ValidationRule createUsernameSyntaxRule() {
+		ValidationDescription description = createDescription("username.rule.syntax");
+		return new RegexRule(description, loginModule.getUsernamePattern());
+	}
+
+	protected ValidationRule createBlackListRule() {
+		ValidationDescription description = createDescription("username.rule.blacklist");
+		return new UsernameBlackListRule(description);
+	}
+	
+	private ValidationRule createUsernameExistsRule() {
+		ValidationDescription description = createDescription("username.rule.in.use");
+		return new UsernameInUseRule(description);
+	}
+	
+	private ValidationDescription createDescription(String i18nKey) {
+		return new TranslatedDescription(createTranslator(), i18nKey);
+	}
+	
+	protected Translator createTranslator() {
+		// The user locale is set later, so use the default locale to construct the translator.
+		return Util.createPackageTranslator(LoginModule.class, Locale.getDefault());
+	}
+}
diff --git a/src/main/java/org/olat/login/validation/ValidationDescription.java b/src/main/java/org/olat/login/validation/ValidationDescription.java
new file mode 100644
index 0000000000000000000000000000000000000000..7678a31f268ef4a2c452ccb83f1bdf1d4c0e006a
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/ValidationDescription.java
@@ -0,0 +1,34 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import java.util.Locale;
+
+/**
+ * 
+ * Initial date: 13 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public interface ValidationDescription {
+
+	public String getText(Locale locale);
+	
+}
diff --git a/src/main/java/org/olat/login/validation/ValidationResult.java b/src/main/java/org/olat/login/validation/ValidationResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..19145a77a664aaca450e0d87270d6eb5c0c18485
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/ValidationResult.java
@@ -0,0 +1,36 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import java.util.List;
+
+/**
+ * 
+ * Initial date: 12 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public interface ValidationResult {
+	
+	public boolean isValid();
+	
+	public List<ValidationDescription> getInvalidDescriptions();
+
+}
diff --git a/src/main/java/org/olat/login/validation/ValidationRule.java b/src/main/java/org/olat/login/validation/ValidationRule.java
new file mode 100644
index 0000000000000000000000000000000000000000..2089e520135366f71116c919c2155ad1fd5c48e2
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/ValidationRule.java
@@ -0,0 +1,42 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 12 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public interface ValidationRule {
+	
+	public boolean validate(String value, Identity identity);
+	
+	public ValidationDescription getDescription();
+
+	/**
+	 *
+	 * @return true if a rule uses the identity to validate the password
+	 */
+	public boolean isIdentityRule();
+
+}
diff --git a/src/main/java/org/olat/login/validation/ValidationRulesProvider.java b/src/main/java/org/olat/login/validation/ValidationRulesProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..13d9a6013ca078bb9afeed0735f36006e5aa438e
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/ValidationRulesProvider.java
@@ -0,0 +1,34 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import java.util.List;
+
+/**
+ * 
+ * Initial date: 12 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public interface ValidationRulesProvider {
+
+	public List<ValidationRule> getRules();
+
+}
diff --git a/src/main/java/org/olat/login/validation/ValidationRulesProviderBuilder.java b/src/main/java/org/olat/login/validation/ValidationRulesProviderBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..936646271108bdf5783d5ab82a54e25a640b6980
--- /dev/null
+++ b/src/main/java/org/olat/login/validation/ValidationRulesProviderBuilder.java
@@ -0,0 +1,58 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 
+ * Initial date: 19 Jun 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class ValidationRulesProviderBuilder {
+	
+	private final List<ValidationRule> rules = new ArrayList<>();
+	
+	public ValidationRulesProviderBuilder add(ValidationRule rule) {
+		rules.add(rule);
+		return this;
+	}
+
+	public ValidationRulesProvider create() {
+		return new ValidationRulesProviderImpl(rules);
+	}
+
+	private static class ValidationRulesProviderImpl implements ValidationRulesProvider {
+		
+		private final List<ValidationRule> rules;
+		
+		private ValidationRulesProviderImpl(List<ValidationRule> rules) {
+			this.rules = new ArrayList<>(rules);
+		}
+
+		@Override
+		public List<ValidationRule> getRules() {
+			return rules;
+		}
+
+	}
+}
diff --git a/src/main/java/org/olat/registration/PwChangeForm.java b/src/main/java/org/olat/registration/PwChangeForm.java
index ddde5d35fdeb82ed96b3691d8799bfb2bb421416..47e9cd57449dfd99891df6f9f283cef4ec4dbbf6 100644
--- a/src/main/java/org/olat/registration/PwChangeForm.java
+++ b/src/main/java/org/olat/registration/PwChangeForm.java
@@ -25,6 +25,8 @@
 
 package org.olat.registration;
 
+import static org.olat.login.ui.LoginUIFactory.formatDescriptionAsList;
+
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -36,8 +38,9 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.Identity;
 import org.olat.core.util.Util;
 import org.olat.login.auth.OLATAuthManager;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
 import org.olat.user.ChangePasswordForm;
-import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -51,28 +54,26 @@ public class PwChangeForm extends FormBasicController {
 	private TextElement newpass2; // confirm
 	
 	private final TemporaryKey tempKey;
-	private Identity identityToChange;
+	private final Identity identityToChange;
+	private final SyntaxValidator syntaxValidator;
 	
 	@Autowired
 	private RegistrationManager rm;
 	@Autowired
-	private UserManager userManager;
-	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
-	private OLATAuthManager olatAuthenticationSpi;
+	private OLATAuthManager olatAuthManager;
 	
 	public PwChangeForm(UserRequest ureq, WindowControl wControl, Identity identityToChange, TemporaryKey tempKey) {
 		super(ureq, wControl, null, Util.createPackageTranslator(ChangePasswordForm.class, ureq.getLocale()));
 		this.identityToChange = identityToChange;
 		this.tempKey = tempKey;
+		this.syntaxValidator = olatAuthManager.createPasswordSytaxValidator();
 		initForm(ureq);
 	}
 	
 	public PwChangeForm(UserRequest ureq, WindowControl wControl, TemporaryKey tempKey) {
-		super(ureq, wControl, null, Util.createPackageTranslator(ChangePasswordForm.class, ureq.getLocale()));
-		this.tempKey = tempKey;
-		initForm(ureq);
+		this(ureq, wControl, null, tempKey);
 	}
 
 	@Override
@@ -80,11 +81,11 @@ public class PwChangeForm extends FormBasicController {
 		boolean allOk = super.validateFormLogic(ureq);
 		
 		newpass1.clearError();
-		if (!userManager.syntaxCheckOlatPassword(newpass1.getValue())) {
-			newpass1.setErrorKey("form.checkPassword", null);
-			allOk &= false;
-		} else if(!olatAuthenticationSpi.checkCredentialHistory(getIdentityToChange(), newpass1.getValue())) {
-			newpass1.setErrorKey("form.checkPassword.history", null);
+		String newPassword = newpass1.getValue();
+		ValidationResult validationResult = syntaxValidator.validate(newPassword, getIdentityToChange());
+		if (!validationResult.isValid()) {
+			String descriptions = formatDescriptionAsList(validationResult.getInvalidDescriptions(), getLocale());
+			newpass1.setErrorKey("error.password.invalid", new String[] { descriptions });
 			allOk &= false;
 		}
 		
@@ -128,15 +129,18 @@ public class PwChangeForm extends FormBasicController {
 	 * @param s The identity to change the password.
 	 */
 	private boolean saveFormData(Identity s) {
-		return olatAuthenticationSpi.changePasswordByPasswordForgottenLink(s, newpass1.getValue());	
+		return olatAuthManager.changePasswordByPasswordForgottenLink(s, newpass1.getValue());	
 	}
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		setFormTitle("form.password.enter.new");
-		newpass1 = uifactory.addPasswordElement("newpass1",  "form.password.new1", 128, "", formLayout);
+		String descriptions = formatDescriptionAsList(syntaxValidator.getAllDescriptions(), getLocale());
+		setFormDescription("form.password.rules", new String[] { descriptions });
+		
+		newpass1 = uifactory.addPasswordElement("newpass1",  "form.password.new1", 5000, "", formLayout);
 		newpass1.setAutocomplete("new-password");
-		newpass2 = uifactory.addPasswordElement("newpass2",  "form.password.new2", 128, "", formLayout);
+		newpass2 = uifactory.addPasswordElement("newpass2",  "form.password.new2", 5000, "", formLayout);
 		newpass2.setAutocomplete("new-password");
 		uifactory.addFormSubmitButton("submit", formLayout);
 	}
diff --git a/src/main/java/org/olat/registration/RegistrationForm2.java b/src/main/java/org/olat/registration/RegistrationForm2.java
index 70c8dbff7d81a5b54aa35c4323b44de0fc88ad81..3ba3e7604c2f2d3adf08b34e8407fdee888bbe99 100644
--- a/src/main/java/org/olat/registration/RegistrationForm2.java
+++ b/src/main/java/org/olat/registration/RegistrationForm2.java
@@ -25,11 +25,12 @@
 
 package org.olat.registration;
 
+import static org.olat.login.ui.LoginUIFactory.formatDescriptionAsList;
+
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.olat.basesecurity.BaseSecurity;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -46,9 +47,11 @@ import org.olat.core.id.Identity;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.login.auth.OLATAuthManager;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
 import org.olat.user.ChangePasswordForm;
 import org.olat.user.UserManager;
-import org.olat.user.UserModule;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -65,7 +68,7 @@ public class RegistrationForm2 extends FormBasicController {
 	private final Map<String,FormItem> propFormItems = new HashMap<>();
 	
 	private SingleSelection lang;
-	private TextElement username;
+	private TextElement usernameEl;
 	private StaticTextElement usernameStatic;
 	private TextElement newpass1;
 	private TextElement newpass2; // confirm
@@ -73,28 +76,24 @@ public class RegistrationForm2 extends FormBasicController {
 	private final String proposedUsername;
 	private final boolean userInUse;
 	private final boolean usernameReadonly;
+	private final SyntaxValidator passwordSyntaxValidator;
+	private final SyntaxValidator usernameSyntaxValidator;
 
-	@Autowired
-	private UserModule userModule;
 	@Autowired
 	private I18nManager i18nManager;
 	@Autowired
 	private UserManager userManager;
 	@Autowired
-	private BaseSecurity securityManager;
+	private OLATAuthManager olatAuthManager;
 	
-	/**
-	 * @param name
-	 * @param languageKey
-	 */
-
 	public RegistrationForm2(UserRequest ureq, WindowControl wControl, String languageKey, String proposedUsername, boolean userInUse, boolean usernameReadonly) {
 		super(ureq, wControl, null, Util.createPackageTranslator(ChangePasswordForm.class, ureq.getLocale()));
-
 		this.languageKey = languageKey;
 		this.proposedUsername = proposedUsername;
 		this.userInUse = userInUse;
 		this.usernameReadonly = usernameReadonly;
+		this.passwordSyntaxValidator = olatAuthManager.createPasswordSytaxValidator();
+		this.usernameSyntaxValidator = olatAuthManager.createUsernameSytaxValidator();
 
 		initForm(ureq);
 	}
@@ -121,23 +120,25 @@ public class RegistrationForm2 extends FormBasicController {
 	}
 	
 	protected String getLogin() {
-		if(username != null) {
-			return username.getValue().trim();
+		if(usernameEl != null) {
+			return usernameEl.getValue().trim();
 		} else if (usernameStatic != null) {
 			return usernameStatic.getValue().trim();
 		}
 		return null;
 	}
+	
 	private void setLogin(String login) {
-		if(username != null) {
-			username.setValue(login);
+		if(usernameEl != null) {
+			usernameEl.setValue(login);
 		} else if (usernameStatic != null) {
 			usernameStatic.setValue(login);
 		}
 	}
+	
 	private void setLoginErrorKey(String errorKey) {
-		if(username != null) {
-			username.setErrorKey(errorKey, new String[0]);
+		if(usernameEl != null) {
+			usernameEl.setErrorKey(errorKey, new String[0]);
 		} else if (usernameStatic != null) {
 			usernameStatic.setErrorKey(errorKey, new String[0]);
 		}
@@ -146,12 +147,10 @@ public class RegistrationForm2 extends FormBasicController {
 	protected String getPassword() {
 		return newpass1.getValue().trim();
 	}
+	
 	protected FormItem getPropFormItem(String k) {
 		return propFormItems.get(k);
 	}
-	/**
-	 * Initialize the form
-	 */
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
@@ -184,8 +183,8 @@ public class RegistrationForm2 extends FormBasicController {
 		if(usernameReadonly) {
 			usernameStatic = uifactory.addStaticTextElement("username", "user.login", proposedUsername, formLayout);
 		} else {
-			username = uifactory.addTextElement("username",  "user.login", 128, "", formLayout);
-			username.setMandatory(true);
+			usernameEl = uifactory.addTextElement("username",  "user.login", 128, "", formLayout);
+			usernameEl.setMandatory(true);
 		}
 		
 		if(proposedUsername != null) {
@@ -195,10 +194,13 @@ public class RegistrationForm2 extends FormBasicController {
 			setLoginErrorKey("form.check6");
 		}
 		
-		newpass1 = uifactory.addPasswordElement("newpass1",  "form.password.new1", 128, "", formLayout);
+		String descriptions = formatDescriptionAsList(passwordSyntaxValidator.getAllDescriptions(), getLocale());
+		uifactory.addStaticTextElement("form.password.rules", null,
+				translate("form.password.rules", new String[] { descriptions }), formLayout);
+		newpass1 = uifactory.addPasswordElement("newpass1",  "form.password.new1", 5000, "", formLayout);
 		newpass1.setMandatory(true);
 		newpass1.setAutocomplete("new-password");
-		newpass2 = uifactory.addPasswordElement("newpass2",  "form.password.new2", 128, "", formLayout);
+		newpass2 = uifactory.addPasswordElement("newpass2",  "form.password.new2", 5000, "", formLayout);
 		newpass2.setMandatory(true);
 		newpass2.setAutocomplete("new-password");
 	
@@ -212,45 +214,57 @@ public class RegistrationForm2 extends FormBasicController {
 
 	@Override
 	protected boolean validateFormLogic (UserRequest ureq) {
+		boolean allOk = true;
+		
 		// validate each user field
 		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
 			FormItem fi = propFormItems.get(userPropertyHandler.getName());
 			if (!userPropertyHandler.isValid(null, fi, null)) {
-				return false;
+				allOk &= false;
 			}
 		}
 		
-		if (!UserManager.getInstance().syntaxCheckOlatLogin(getLogin())) {
-			setLoginErrorKey("form.check3");
-			return false;
-		}
+		// Transient identity for validations
+		Identity newIdentity = getIdentity();
 		
-		Identity s = securityManager.findIdentityByName(getLogin());
-		if (s != null || userModule.isLoginOnBlacklist(getLogin())) {
-			setLoginErrorKey("form.check6");
-			return false;
+		// validate if username does match the syntactical login requirements
+		usernameEl.clearError();
+		String username = usernameEl.getValue();
+		if (!StringHelper.containsNonWhitespace(username)) {
+			usernameEl.setErrorKey("form.legende.mandatory", null);
+			allOk &= false;
+		} else {
+			ValidationResult validationResult = usernameSyntaxValidator.validate(username, newIdentity);
+			if (!validationResult.isValid()) {
+				String descriptions = validationResult.getInvalidDescriptions().get(0).getText(getLocale());
+				usernameEl.setErrorKey("error.username.invalid", new String[] { descriptions });
+				allOk &= false;
+			}
 		}
 		
 		if (newpass1.getValue().equals("")) {
 			newpass1.setErrorKey("form.check4", null);
-			return false;
+			allOk &= false;
 		}
 		
 		if (newpass2.getValue().equals("")) {
 			newpass2.setErrorKey("form.check4", null);
-			return false;
+			allOk &= false;
 		}
 		
-		if (!UserManager.getInstance().syntaxCheckOlatPassword(newpass1.getValue())) {
-			newpass1.setErrorKey("form.checkPassword", null);
-			return false;
-		}
+		String newPassword = newpass1.getValue();
+		ValidationResult validationResult = passwordSyntaxValidator.validate(newPassword, newIdentity);
+		if (!validationResult.isValid()) {
+			String descriptions = formatDescriptionAsList(validationResult.getInvalidDescriptions(), getLocale());
+			newpass1.setErrorKey("error.password.invalid", new String[] { descriptions });
+			allOk &= false;
+		} 
 		if (!newpass1.getValue().equals(newpass2.getValue())) {
 			newpass2.setErrorKey("form.check5", null);
-			// OO-92 : must return false, if passwords don't match!
-			return false;
+			allOk &= false;
 		}
-		return true;
+		
+		return allOk & super.validateFormLogic(ureq);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/registration/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/registration/_i18n/LocalStrings_de.properties
index 2b1855f7a8917567309a33bacb1b89cbf31528ca..b480cd44f7f79c9be47f6f69b5d7de8195953495 100644
--- a/src/main/java/org/olat/registration/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/registration/_i18n/LocalStrings_de.properties
@@ -58,6 +58,7 @@ form.password.enter.new=Passwort neu setzen
 form.password.error.nomatch=Beide Passw\u00F6rter m\u00FCssen gleich sein
 form.password.new1=Neues Passwort
 form.password.new2=Passwort best\u00E4tigen
+form.password.rules=$org.olat.user\:form.password.validation.rules
 login.body=Sie sind bereits in OpenOLAT registriert unter dem Benutzernamen\: {0} \n\nFalls Sie diese E-Mail unaufgefordert erhalten haben, l\u00F6schen Sie ganz einfach diese E-Mail.\n\nIhr OpenOLAT-Team \n
 login.subject=Bereits vorhandene Registrierung in OpenOLAT
 loginhelp=Der Benutzername<ul><li>muss mindestens 4 Zeichen lang sein</li><li>darf nur Ziffern und / oder Kleinbuchstaben enthalten (keine Umlaute, keine Sonderzeichen ausser .-_)</li><li>kann sp\u00E4ter nicht mehr ge\u00E4ndert werden</li></ul>
@@ -72,7 +73,7 @@ pw.change.sms=SMS Authentifizierung starten
 pw.change.sms.descr=Sie haben eine Mobile Telefonnummer in OpenOLAT hinterlegt. Sie k\u00F6nnen sich daher \u00FCber SMS authentifizieren. W\u00E4hlen Sie den untenstehenden Button, um die SMS-Authentifizierung zu starten\:
 pw.change.sms.title=SMS Authentifizierung
 pwchange.headline=<p><b>Schl\u00FCssel f\u00FCr neues OpenOLAT-Passwort</b></p>
-pwchange.body=<p>Klicken Sie <a href='{0}/dmz/pwchange/index.html?key\={1}&language\={2}'>hier um Ihr OpenOLAT Passwort neu zu setzen</a>. \nAnschließend k\u00F6nnen Sie sich bei <a href='{0}/dmz/1%3A1%3Aomain_loging%3A1%3A0%3Acid%3Alogin/?lp\=OLAT'>OpenOLAT anmelden</a>.</p> 
+pwchange.body=<p>Klicken Sie <a href='{0}/dmz/pwchange/index.html?key\={1}&language\={2}'>hier um Ihr OpenOLAT Passwort neu zu setzen</a>. \nAnschlie\uFFFDend k\u00F6nnen Sie sich bei <a href='{0}/dmz/1%3A1%3Aomain_loging%3A1%3A0%3Acid%3Alogin/?lp\=OLAT'>OpenOLAT anmelden</a>.</p> 
 pwchange.body.alt=<p>Falls Ihr Emailprogramm HTML nicht unterst\u00FCtzt, kopieren Sie den folgenden Link in Ihren Webbrowser: </br><a href='{0}/dmz/pwchange/index.html?key\={1}&language\={2}'>{0}/dmz/pwchange/index.html?key\={1}&language\={2}</a><p>
 pwchange.homelink=Klicken Sie hier um sich anzumelden
 pwchange.intro=Sie oder eine andere Person haben f\u00FCr den OpenOLAT-Benutzeraccount {0} ein neues Passwort angefordert.\n\n
diff --git a/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties
index d16e9d827951c3f1e51ce6636c71a2eee8a82f65..03acdab8a473515034a658010420e48c9f6f5ee4 100644
--- a/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/registration/_i18n/LocalStrings_en.properties
@@ -58,6 +58,7 @@ form.password.enter.new=Set new password
 form.password.error.nomatch=Passwords do not match.
 form.password.new1=New password
 form.password.new2=Confirm password
+form.password.rules=$org.olat.user\:form.password.validation.rules
 login.body=You are already registered in OpenOLAT. Your user name is\: {0}.\n\nIn case you got this e-mail unwanted, please delete it.\n\nYour OpenOLAT team.\n
 login.subject=You are already registered in OpenOLAT.
 loginhelp=A user name<ul><li>must contain at least 4 characters</li><li>may only contain digits and/or lower case letters (no special digits or umlauts except for . - _)</li><li>cannot be changed later on</li></ul>
diff --git a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java
index cee7eed57466bea393415c1874e7eb9b786e8585..a6edf76b3145973ae858695c246f02e0dbd69583 100644
--- a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java
+++ b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java
@@ -262,7 +262,7 @@ public class ShibbolethRegistrationController extends DefaultController implemen
 			}
 		} else if (source == regForm) {
 			if (event == Event.DONE_EVENT) {
-				String choosenLogin = regForm.getLogin();
+				String choosenLogin = regForm.getUsernameEl();
 				Identity identity = securityManager.findIdentityByName(choosenLogin);
 
 
@@ -304,7 +304,7 @@ public class ShibbolethRegistrationController extends DefaultController implemen
 					if(regForm == null ) {
 						choosenLogin = proposedUsername;
 					} else {
-						choosenLogin = regForm.getLogin();
+						choosenLogin = regForm.getUsernameEl();
 					}
 
 					// check if login has been taken by another user in the meantime...
diff --git a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationForm.java b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationForm.java
index 7a5ed0b8b9a49093d0f22e69839b6d27c541999e..626f6138bfd6b2ad170dc0b85955459f93029392 100644
--- a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationForm.java
+++ b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationForm.java
@@ -25,6 +25,7 @@
 
 package org.olat.shibboleth;
 
+import org.olat.admin.user.imp.TransientIdentity;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
@@ -32,8 +33,12 @@ import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
-import org.olat.user.UserManager;
-import org.olat.user.UserModule;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.Util;
+import org.olat.login.auth.OLATAuthManager;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
+import org.olat.user.ChangePasswordForm;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -47,42 +52,48 @@ import org.springframework.beans.factory.annotation.Autowired;
 
 public class ShibbolethRegistrationForm extends FormBasicController {
 
-	private TextElement login;
+	private TextElement usernameEl;
 	private String proposedUsername;
-	
-	@Autowired
-	private UserModule userModule;
+
+	private final SyntaxValidator usernameSyntaxValidator;
+
 	@Autowired
-	private UserManager userManager;
-	/**
-	 * @param name
-	 * @param translator
-	 */
+	private OLATAuthManager olatAuthManager;
 
 	public ShibbolethRegistrationForm(UserRequest ureq, WindowControl wControl, String proposedUsername) {
 		super(ureq, wControl);
+		setTranslator(Util.createPackageTranslator(ChangePasswordForm.class, ureq.getLocale(), getTranslator()));
 		this.proposedUsername = proposedUsername;
+		this.usernameSyntaxValidator = olatAuthManager.createUsernameSytaxValidator();
 		initForm(ureq);
 	}
 	
 	@Override
 	protected boolean validateFormLogic(UserRequest ureq) {
-		if (login.isEmpty("srf.error.loginempty")) return false;
-		if (!userManager.syntaxCheckOlatLogin(getLogin())) {
-			login.setErrorKey("srf.error.loginregexp", null);
+		// validate if username does match the syntactical login requirements
+		usernameEl.clearError();
+		String username = usernameEl.getValue();
+		if (!StringHelper.containsNonWhitespace(username)) {
+			usernameEl.setErrorKey("form.legende.mandatory", null);
 			return false;
-		}
-		if (userModule.isLoginOnBlacklist(getLogin())) {
-			login.setErrorKey("srf.error.blacklist", null);
+		} 
+		
+		TransientIdentity newIdentity = new TransientIdentity();
+		newIdentity.setName(username);
+		ValidationResult validationResult = usernameSyntaxValidator.validate(username, newIdentity);
+		if (!validationResult.isValid()) {
+			String descriptions = validationResult.getInvalidDescriptions().get(0).getText(getLocale());
+			usernameEl.setErrorKey("error.username.invalid", new String[] { descriptions });
 			return false;
 		}
+		
 		return true;
 	}
 
 	/**
 	 * @return Login field.
 	 */
-	protected String getLogin() { return login.getValue(); }
+	protected String getUsernameEl() { return usernameEl.getValue(); }
 
 	@Override
 	protected void formOK(UserRequest ureq) {
@@ -92,8 +103,8 @@ public class ShibbolethRegistrationForm extends FormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		String initialValue = proposedUsername == null ? "" : proposedUsername;
-		login = uifactory.addTextElement("srf_login", "srf.login", 128, initialValue, formLayout);
-		login.setExampleKey("srf.login.example", null);
+		usernameEl = uifactory.addTextElement("srf_login", "srf.login", 128, initialValue, formLayout);
+		usernameEl.setExampleKey("srf.login.example", null);
 		uifactory.addFormSubmitButton("save", formLayout);
 	}
 
diff --git a/src/main/java/org/olat/user/ChangePasswordController.java b/src/main/java/org/olat/user/ChangePasswordController.java
index 685c21378d5bbc1fde2ca763a2e4395f21e68e09..dab7105d02797bd311c3bff3d6ef070bc7405433 100644
--- a/src/main/java/org/olat/user/ChangePasswordController.java
+++ b/src/main/java/org/olat/user/ChangePasswordController.java
@@ -87,10 +87,6 @@ public class ChangePasswordController extends BasicController implements Support
 	@Autowired
 	private OLATAuthManager olatAuthenticationSpi;
 
-	/**
-	 * @param ureq
-	 * @param wControl
-	 */
 	public ChangePasswordController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl);
 
diff --git a/src/main/java/org/olat/user/ChangePasswordForm.java b/src/main/java/org/olat/user/ChangePasswordForm.java
index 10c9f038a628e31514d1c0ba114b1500cbfa4827..9ac8b37cfe2cfcc06cff2ad4504eac7dc9231e1a 100644
--- a/src/main/java/org/olat/user/ChangePasswordForm.java
+++ b/src/main/java/org/olat/user/ChangePasswordForm.java
@@ -25,6 +25,8 @@
 
 package org.olat.user;
 
+import static org.olat.login.ui.LoginUIFactory.formatDescriptionAsList;
+
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
@@ -35,6 +37,8 @@ import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.Identity;
 import org.olat.login.auth.OLATAuthManager;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
 import org.springframework.beans.factory.annotation.Autowired;
 
 
@@ -56,51 +60,55 @@ public class ChangePasswordForm extends FormBasicController {
 	private String oldCred = "";
 	private String newCred = "";
 	
+	private final SyntaxValidator syntaxValidator;
 	private final Identity identityToChange;
 	
 	@Autowired
-	private UserManager userManager;
-	@Autowired
-	private OLATAuthManager olatAuthenticationSpi;
+	private OLATAuthManager olatAuthManager;
 
-	/**
-	 * @param name
-	 */
 	public ChangePasswordForm(UserRequest ureq, WindowControl wControl, Identity identityToChange) {
 		super(ureq, wControl);
 		this.identityToChange = identityToChange;
+		this.syntaxValidator = olatAuthManager.createPasswordSytaxValidator();
 		initForm(ureq);
 	}
 
-	/**
-	 * @return Old password field value.
-	 */
 	public String getOldPasswordValue() {
 		return oldCred;
 	}
 	
-	/**
-	 * @return New password field value.
-	 */
 	public String getNewPasswordValue() {
 		return newCred;
 	}
 
 	@Override
-	protected void formOK(UserRequest ureq) {
-		oldCred = oldCredEl.getValue(); 
-		newCred = newCredEl.getValue();
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		String descriptions = formatDescriptionAsList(syntaxValidator.getAllDescriptions(), getLocale());
+		setFormDescription("form.password.validation.rules", new String[] { descriptions });
 		
-		oldCredEl.setValue("");
-		newCredEl.setValue("");
-		newCredConfirmationEl.setValue("");
+		oldCredEl = uifactory.addPasswordElement("oldpass", "form.password.old", 5000, "", formLayout);
+		oldCredEl.setElementCssClass("o_sel_home_pwd_old");
+		oldCredEl.setNotEmptyCheck("form.please.enter.old");
+		oldCredEl.setMandatory(true);
 		
-		fireEvent (ureq, Event.DONE_EVENT); 
-	}
-	
-	@Override
-	protected void formCancelled(UserRequest ureq) {
-		fireEvent (ureq, Event.CANCELLED_EVENT);
+		newCredEl = uifactory.addPasswordElement("newpass1",  "form.password.new1", 5000, "", formLayout);
+		newCredEl.setNotEmptyCheck("form.please.enter.new");
+		newCredEl.setElementCssClass("o_sel_home_pwd_new_1");
+		newCredEl.setAutocomplete("new-password");
+		newCredEl.setMandatory(true);
+		
+		newCredConfirmationEl = uifactory.addPasswordElement("newpass2",  "form.password.new2", 5000, "", formLayout);
+		newCredConfirmationEl.setNotEmptyCheck("form.please.enter.new");
+		newCredConfirmationEl.setElementCssClass("o_sel_home_pwd_new_2");
+		newCredConfirmationEl.setAutocomplete("new-password");
+		newCredConfirmationEl.setMandatory(true);
+		
+		// Button layout
+		FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator());
+		buttonLayout.setElementCssClass("o_sel_home_pwd_buttons");
+		formLayout.add(buttonLayout);
+		uifactory.addFormSubmitButton("submit", buttonLayout);
+		uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl());	
 	}
 	
 	@Override
@@ -108,18 +116,16 @@ public class ChangePasswordForm extends FormBasicController {
 		boolean allOk = super.validateFormLogic(ureq);
 		
 		newCredEl.clearError();
-		if (!userManager.syntaxCheckOlatPassword(newCredEl.getValue())) {
-			newCredEl.setErrorKey("form.checkPassword", null);
-			allOk &= false;
-		} else if(!olatAuthenticationSpi.checkCredentialHistory(identityToChange, newCredEl.getValue())) {
-			newCredEl.setErrorKey("form.checkPassword.history", null);
+		String newPassword = newCredEl.getValue();
+		ValidationResult validationResult = syntaxValidator.validate(newPassword, identityToChange);
+		if (!validationResult.isValid()) {
+			String descriptions = formatDescriptionAsList(validationResult.getInvalidDescriptions(), getLocale());
+			newCredEl.setErrorKey("error.password.invalid", new String[] { descriptions });
 			allOk &= false;
 		}
 
 		newCredConfirmationEl.clearError();
 		if (!newCredEl.getValue().equals(newCredConfirmationEl.getValue())) {
-			newCredEl.setValue("");
-			newCredConfirmationEl.setValue("");
 			newCredConfirmationEl.setErrorKey("error.password.nomatch", null);
 			allOk &= false;
 		}
@@ -128,30 +134,20 @@ public class ChangePasswordForm extends FormBasicController {
 	}
 
 	@Override
-	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-		oldCredEl = uifactory.addPasswordElement("oldpass", "form.password.old", 128, "", formLayout);
-		oldCredEl.setElementCssClass("o_sel_home_pwd_old");
-		oldCredEl.setNotEmptyCheck("form.please.enter.old");
-		oldCredEl.setMandatory(true);
-		
-		newCredEl = uifactory.addPasswordElement("newpass1",  "form.password.new1", 128, "", formLayout);
-		newCredEl.setNotEmptyCheck("form.please.enter.new");
-		newCredEl.setElementCssClass("o_sel_home_pwd_new_1");
-		newCredEl.setAutocomplete("new-password");
-		newCredEl.setMandatory(true);
+	protected void formOK(UserRequest ureq) {
+		oldCred = oldCredEl.getValue(); 
+		newCred = newCredEl.getValue();
 		
-		newCredConfirmationEl = uifactory.addPasswordElement("newpass2",  "form.password.new2", 128, "", formLayout);
-		newCredConfirmationEl.setNotEmptyCheck("form.please.enter.new");
-		newCredConfirmationEl.setElementCssClass("o_sel_home_pwd_new_2");
-		newCredConfirmationEl.setAutocomplete("new-password");
-		newCredConfirmationEl.setMandatory(true);
+		oldCredEl.setValue("");
+		newCredEl.setValue("");
+		newCredConfirmationEl.setValue("");
 		
-		// Button layout
-		FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator());
-		buttonLayout.setElementCssClass("o_sel_home_pwd_buttons");
-		formLayout.add(buttonLayout);
-		uifactory.addFormSubmitButton("submit", buttonLayout);
-		uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl());	
+		fireEvent(ureq, Event.DONE_EVENT); 
+	}
+	
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent (ureq, Event.CANCELLED_EVENT);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/user/UserManager.java b/src/main/java/org/olat/user/UserManager.java
index 0cef00a5a731025e9c7ebc6bb7faffb318079ba8..b886d260e36ce8bf0730a33db06ba686a5312509 100644
--- a/src/main/java/org/olat/user/UserManager.java
+++ b/src/main/java/org/olat/user/UserManager.java
@@ -54,7 +54,6 @@ public abstract class UserManager {
 	
 	// injected by spring configuration
 	protected UserPropertiesConfig userPropertiesConfig;
-	protected UserNameAndPasswordSyntaxChecker userNameAndPasswordSyntaxChecker;
 
 	/**
 	 * Use getInstance method
@@ -197,26 +196,6 @@ public abstract class UserManager {
 	 */
 	public abstract String getUserCharset(Identity identity);
 
-	/**
-	 * Validates an OLAT password on a syntactical level. 
-	 * 
-	 * @param password The passwort to validate
-	 * @return true if it is valid, false otherwhise
-	 */
-	public boolean syntaxCheckOlatPassword(String password) {
-		return userNameAndPasswordSyntaxChecker.syntaxCheckOlatPassword(password);
-	}
-
-	/**
-	 * Check if the login matches.
-	 * 
-	 * @param login
-	 * @return True if synatx is ok.
-	 */
-	public boolean syntaxCheckOlatLogin(String login) {
-		return userNameAndPasswordSyntaxChecker.syntaxCheckOlatLogin(login);
-	}
-
 	public UserPropertiesConfig getUserPropertiesConfig() {
 		return userPropertiesConfig;
 	}
@@ -245,14 +224,6 @@ public abstract class UserManager {
 		return userPropertiesConfig.isUserViewReadOnly(usageIdentifyer, propertyHandler);
 	}
 	
-	/**
-	 * Spring setter
-	 * @param userNameAndPasswordSyntaxChecker
-	 */
-	public void setUserNameAndPasswordSyntaxChecker(UserNameAndPasswordSyntaxChecker userNameAndPasswordSyntaxChecker) {
-		this.userNameAndPasswordSyntaxChecker = userNameAndPasswordSyntaxChecker;
-	}
-
 	/**
 	 * Spring setter
 	 * @param userPropertiesConfig
diff --git a/src/main/java/org/olat/user/UserNameAndPasswordSyntaxChecker.java b/src/main/java/org/olat/user/UserNameAndPasswordSyntaxChecker.java
deleted file mode 100644
index 204e8c3fbb15790179186bf174e890d86fbe763a..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/user/UserNameAndPasswordSyntaxChecker.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.user;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * <h3>Description:</h3>
- * This login name and password syntax checker provides methods to check if a
- * user name and a password is syntactically correct. Inherit from this class
- * and configure your own checker in the spring user manager configuration to
- * allow different user names that the default (e.g. if you want to use email
- * addresses as login names)
- * <p>
- * Initial Date: 31.07.2007 <br>
- * 
- * @author Florian Gnaegi, frentix GmbH, http://www.frentix.com
- */
-public class UserNameAndPasswordSyntaxChecker {
-
-	/**
-	 * Validates an OLAT password on a syntactical level. A password is valid when
-	 * it matches the following requrements:<br>
-	 * <ol>
-	 * <li />Only numbers (0-9), letters (a-z, A-Z) and the following special
-	 * characters (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~) are allowed
-	 * <li />Size is between 4 and 128 characters
-	 * <li />At least one number and at least one letter must be used
-	 * </ol>
-	 * 
-	 * @param password The passwort to validate
-	 * @return true if it is valid, false otherwhise
-	 */
-	public boolean syntaxCheckOlatPassword(String password) {
-		Pattern p = Pattern.compile("^\\p{Graph}{4,128}$");
-		Matcher m = p.matcher(password);
-
-		if (m.matches()) {
-			if (!password.matches(".*['\"]+.*")) {
-				if (password.matches(".*\\p{Alpha}+.*")) {
-					if (password.matches(".*\\p{Digit}+.*")) return true;
-				}
-			}
-		}
-		return false;
-	}
-
-	/**
-	 * Checks for a valid login name. The method does only check if the name is
-	 * syntactically correct. It does not check if the name is valid
-	 * 
-	 * @param login
-	 * @return True if synatx is ok.
-	 */
-	public boolean syntaxCheckOlatLogin(String login) {
-		// Allow only alphanumeric login names - must be like this to generate
-		// valid jabber user ID's. No support for generic UTF-8 login names...
-		//if you want to user email adresses as login names check the instant messaging config as you have to replace the @ for jabber names
-		return login.matches("[0-9a-z\\.\\-_]{3,64}");
-	}
-
-}
diff --git a/src/main/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithEmail.java b/src/main/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithEmail.java
deleted file mode 100644
index 97f34af1e9f46b80bd887bd6956b6444b9fbfe90..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithEmail.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.user;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * <h3>Description:</h3>
- * This login name and password syntax checker provides methods to check if a
- * user name and a password is syntactically correct. Inherit from this class
- * and configure your own checker in the spring user manager configuration to
- * allow different user names that the default (e.g. if you want to use email
- * addresses as login names)
- * <p>
- * Initial Date: 5.06.2008 <br>
- * 
- * @author Roman Haag, frentix GmbH, http://www.frentix.com
- */
-public class UserNameAndPasswordSyntaxCheckerWithEmail extends UserNameAndPasswordSyntaxChecker {
-
-	/**
-	 * Validates an OLAT password on a syntactical level. A password is valid when
-	 * it matches the following requrements:<br>
-	 * <ol>
-	 * <li />Only numbers (0-9), letters (a-z, A-Z) and the following special
-	 * characters (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~) are allowed
-	 * <li />Size is between 4 and 128 characters
-	 * <li />At least one number and at least one letter must be used
-	 * </ol>
-	 * 
-	 * @param password The passwort to validate
-	 * @return true if it is valid, false otherwhise
-	 */
-	@Override
-	public boolean syntaxCheckOlatPassword(String password) {
-		Pattern p = Pattern.compile("^\\p{Graph}{4,128}$");
-		Matcher m = p.matcher(password);
-
-		if (m.matches()) {
-			if (!password.matches(".*['\"]+.*")) {
-				if (password.matches(".*\\p{Alpha}+.*")) {
-					if (password.matches(".*\\p{Digit}+.*")) return true;
-				}
-			}
-		}
-		return false;
-	}
-
-	/**
-	 * Checks for a valid login name. The method does only check if the name is
-	 * syntactically correct. It does not check if the name is valid
-	 * 
-	 * @param login
-	 * @return True if syntax is ok.
-	 */
-	@Override
-	public boolean syntaxCheckOlatLogin(String login) {
-		// Allow only alphanumeric login names 
-		// @ is allowed also (will be replaced for Jabber)		
-		return login.matches("[0-9a-z\\.\\-_]{4,64}") || login.matches("[0-9a-z\\.\\-_@]{6,64}");
-	}
-
-}
diff --git a/src/main/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithRegexp.java b/src/main/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithRegexp.java
deleted file mode 100644
index 1c0fe240b9f0734d89c4dcc82b8c558b1dc0ea3d..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithRegexp.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <p>
-* Licensed under the Apache License, Version 2.0 (the "License"); <br>
-* you may not use this file except in compliance with the License.<br>
-* You may obtain a copy of the License at
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <p>
-* Unless required by applicable law or agreed to in writing,<br>
-* software distributed under the License is distributed on an "AS IS" BASIS, <br>
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
-* See the License for the specific language governing permissions and <br>
-* limitations under the License.
-* <p>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.
-*/
-package org.olat.user;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-import org.apache.logging.log4j.Logger;
-import org.olat.core.logging.Tracing;
-
-/**
- * Description:<br>
- * This configurable password and syntax checker can be used if you need a
- * custom loginname / password rule. Don't forget to adapt the corresponding
- * i18n keys.
- * 
- * <P>
- * Initial Date: 15.12.2008 <br>
- * 
- * @author gnaegi
- */
-public class UserNameAndPasswordSyntaxCheckerWithRegexp extends UserNameAndPasswordSyntaxChecker {
-	private static final Logger log = Tracing.createLoggerFor(UserNameAndPasswordSyntaxCheckerWithEmail.class);
-	// precompiled patterns with default values
-	private Pattern passwordPattern = Pattern.compile("^\\p{Graph}{4,128}$");
-	private Pattern usernamePattern = Pattern.compile("[0-9a-z\\.\\-_@]{3,32}");
-
-	/**
-	 * Validates an OLAT password on a syntactical level. A password is valid when
-	 * it matches the requirements that are set in the spring configuration.
-	 * <p>
-	 * 
-	 * @param password The passwort to validate
-	 * @return true if it is valid, false otherwhise
-	 */
-	@Override
-	public boolean syntaxCheckOlatPassword(String password) {
-		Matcher m = passwordPattern.matcher(password);
-		return m.matches();
-	}
-
-	/**
-	 * Checks for a valid user name. The method does only check if the name is
-	 * syntactically correct. It does not check if the name is valid (already in
-	 * use by another user)
-	 * 
-	 * @param login
-	 * @return True if syntax is ok.
-	 */
-	@Override
-	public boolean syntaxCheckOlatLogin(String login) {
-		Matcher m = usernamePattern.matcher(login);
-		return m.matches();
-	}
-
-	/**
-	 * Spring setter to set new password regular expression
-	 * @param passwordRegExp
-	 */
-	public void setPasswordRegExp(String passwordRegExp) {
-		try {
-			passwordPattern = Pattern.compile(passwordRegExp);
-		} catch (PatternSyntaxException e) {
-			log.error("Invalid regular expression::" + passwordRegExp + " for password checker", e);
-		}
-	}
-
-	/**
-	 * Spring setter to set new useranem regular expression
-	 * @param usernameRegExp
-	 */
-	public void setUsernameRegExp(String usernameRegExp) {
-		try {
-			usernamePattern = Pattern.compile(usernameRegExp);
-		} catch (PatternSyntaxException e) {
-			log.error("Invalid regular expression::" + usernameRegExp + " for username checker", e);
-		}
-	}
-}
diff --git a/src/main/java/org/olat/user/WebDAVPasswordController.java b/src/main/java/org/olat/user/WebDAVPasswordController.java
index 89fab88f9dde6e339c486f7cfd1273b84cdb66a7..4a0e0cefb47dcc2bc12d94cfe43f37f24dd59ef6 100644
--- a/src/main/java/org/olat/user/WebDAVPasswordController.java
+++ b/src/main/java/org/olat/user/WebDAVPasswordController.java
@@ -20,6 +20,8 @@
 
 package org.olat.user;
 
+import static org.olat.login.ui.LoginUIFactory.formatDescriptionAsList;
+
 import java.util.List;
 
 import org.olat.basesecurity.Authentication;
@@ -44,6 +46,9 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.login.auth.OLATAuthManager;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationResult;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -60,6 +65,7 @@ public class WebDAVPasswordController extends FormBasicController {
 	private FormSubmit saveButton;
 	private FormCancel cancelButton;
 	private FormLink newButton;
+	private StaticTextElement rulesEl;
 	private TextElement passwordEl;
 	private TextElement confirmPasswordEl;
 	private StaticTextElement usernamesStaticEl;
@@ -67,15 +73,20 @@ public class WebDAVPasswordController extends FormBasicController {
 	private FormLayoutContainer accessDataFlc;
 	private FormLayoutContainer buttonGroupLayout;
 	
+	private final SyntaxValidator syntaxValidator;
+	
 	@Autowired
 	private UserModule userModule;
 	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
+	private OLATAuthManager olatAuthManager;
+	@Autowired
 	private WebDAVAuthManager webDAVAuthManager;
 	
 	public WebDAVPasswordController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl, "pwdav", Util.createPackageTranslator(FolderRunController.class, ureq.getLocale()));
+		this.syntaxValidator = olatAuthManager.createPasswordSytaxValidator();
 		initForm(ureq);
 	}
 	
@@ -118,10 +129,15 @@ public class WebDAVPasswordController extends FormBasicController {
 				String passwordPlaceholder = getTranslator().translate(passwordPlaceholderKey);
 				passwordStaticEl = uifactory.addStaticTextElement("pwdav.password", "pwdav.password", passwordPlaceholder, accessDataFlc);
 
-				passwordEl = uifactory.addPasswordElement("pwdav.password.2", "pwdav.password", 64, "", accessDataFlc);
+				String descriptions = formatDescriptionAsList(syntaxValidator.getAllDescriptions(), getLocale());
+				rulesEl = uifactory.addStaticTextElement("pwdav.password.rules", null,
+						translate("pwdav.password.rules", new String[] { descriptions }), accessDataFlc);
+				rulesEl.setVisible(false);
+				
+				passwordEl = uifactory.addPasswordElement("pwdav.password.2", "pwdav.password", 5000, "", accessDataFlc);
 				passwordEl.setVisible(false);
 				passwordEl.setMandatory(true);
-				confirmPasswordEl = uifactory.addPasswordElement("pwdav.password.confirm", "pwdav.password.confirm", 64, "", accessDataFlc);
+				confirmPasswordEl = uifactory.addPasswordElement("pwdav.password.confirm", "pwdav.password.confirm", 5000, "", accessDataFlc);
 				confirmPasswordEl.setVisible(false);
 				confirmPasswordEl.setMandatory(true);
 
@@ -170,7 +186,7 @@ public class WebDAVPasswordController extends FormBasicController {
 			}
 		}
 		
-		return sb.toString();		
+		return sb.toString();
 	}
 	
 	@Override
@@ -182,16 +198,13 @@ public class WebDAVPasswordController extends FormBasicController {
 	protected boolean validateFormLogic(UserRequest ureq) {
 		boolean allOk = true;
 		if(passwordEl.isVisible()) {
+			passwordEl.clearError();
 			String password = passwordEl.getValue();
-			boolean valid = UserManager.getInstance().syntaxCheckOlatPassword(passwordEl.getValue());
-			if(StringHelper.containsNonWhitespace(password) && valid) {
-				passwordEl.clearError();
-			} else if (!valid){
-				passwordEl.setErrorKey("form.checkPassword", null);
-				allOk = false;
-			} else {
-				passwordEl.setErrorKey("error.password.empty", null);
-				allOk = false;
+			ValidationResult validationResult = syntaxValidator.validate(password, getIdentity());
+			if (!validationResult.isValid()) {
+				String descriptions = formatDescriptionAsList(validationResult.getInvalidDescriptions(), getLocale());
+				passwordEl.setErrorKey("error.password.invalid", new String[] { descriptions });
+				allOk &= false;
 			}
 			
 			String confirmation = confirmPasswordEl.getValue();
@@ -234,6 +247,7 @@ public class WebDAVPasswordController extends FormBasicController {
 		passwordStaticEl.setVisible(!visible);
 		saveButton.setVisible(visible);
 		cancelButton.setVisible(visible);
+		rulesEl.setVisible(visible);
 		passwordEl.setVisible(visible);
 		confirmPasswordEl.setVisible(visible);
 		
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_ar.properties
index 8a4d38f35b1d1b91f76970909666f509bc010056..7e7812d100aedb809b76e34738f12ce03d2d72ee 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_ar.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_ar.properties
@@ -25,8 +25,6 @@ error.password.noauth=\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0
 error.password.nomatch=\u0644\u0627 \u064A\u0648\u062C\u062F \u062A\u0637\u0627\u0628\u0642 \u0628\u064A\u0646 \u0643\u0644\u0645\u062A\u0627\u0646 \u0627\u0644\u0645\u0631\u0648\u0631 \u0627\u0644\u062C\u062F\u064A\u062F\u062A\u0627\u0646.
 form.address=\u0627\u0644\u0639\u0646\u0648\u0627\u0646
 form.charset=\u0645\u062C\u0645\u0648\u0639\u0629 \u0631\u0645\u0648\u0632 \u062A\u0633\u062A\u062E\u062F\u0645 \u0641\u0649 \u0627\u0644\u062A\u0646\u0632\u064A\u0644
-form.checkPassword=\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0627\u0644\u062E\u0627\u0635\u0629 \u0628\u0643 \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u0649 \u0639\u0644\u0649 \u0645\u0627 \u0644\u0627 \u064A\u0642\u0644 \u0639\u0646 4 \u062D\u0631\u0648\u0641 \u0648\u062A\u0634\u0645\u0644 \u0627\u0644\u0623\u0631\u0642\u0627\u0645 \u0648\u0627\u0644\u062D\u0631\u0648\u0641..
-form.checkUsername=\u0623\u0633\u0645\u0627\u0621 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645\u064A\u0646 \u064A\u062C\u0628 \u0623\u0646 \u062A\u062D\u062A\u0648\u0649 \u0639\u0644\u0649 \u0645\u0627 \u0644\u0627 \u064A\u0642\u0644 \u0639\u0646 4 \u0623\u062D\u0631\u0641 \u0648 \u0627\u0644\u062D\u0631\u0648\u0641 \u0641\u0642\u0637 \u0645\u0646 \u0627\u0644\u0623\u0644\u0641 \u0625\u0644\u0649 \u0627\u0644\u064A\u0627\u0621\u060C \u0641\u0636\u0644\u0627 \u0639\u0646 \u0627\u0644\u0623\u0631\u0642\u0627\u0645 \u0645\u0646 0 \u0625\u0644\u0649 9\u060C \u0648\u0628\u0627\u0644\u0625\u0636\u0627\u0641\u0629 \u0625\u0644\u0649 \u0630\u0644\u0643\u060C \u064A\u062C\u0648\u0632 \u0644\u0643 \u0627\u0633\u062A\u062E\u062F\u0627\u0645. _ \u0648-.
 form.description=\u064A\u0631\u062C\u0649 \u0643\u062A\u0627\u0628\u0629 \u0628\u064A\u0627\u0646\u0627\u062A\u0643 \u0627\u0644\u0634\u062E\u0635\u064A\u0629 \u0641\u0649 \u0647\u0630\u0627 \u0627\u0644\u0646\u0645\u0648\u0630\u062C\u060C \u0648\u0639\u0646 \u0637\u0631\u064A\u0642 \u0645\u0631\u0628\u0639\u0627\u062A \u0627\u0644\u0627\u062E\u062A\u064A\u0627\u0631 \u064A\u0645\u0643\u0646\u0643 \u062A\u062D\u062F\u064A\u062F \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u062A\u0649 \u062A\u0631\u064A\u062F \u0623\u0646 \u062A\u0638\u0647\u0631 \u0641\u0649 \u0628\u0637\u0627\u0642\u0629 \u0627\u0644\u062A\u0639\u0627\u0631\u0641 \u0627\u0644\u062E\u0627\u0635\u0629 \u0628\u0643.
 form.email=\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0628\u0631\u064A\u062F \u0627\u0644\u0627\u0644\u0643\u062A\u0631\u0648\u0646\u0649
 form.fields=\u0627\u062E\u062A\u064A\u0627\u0631 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062A
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_bg.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_bg.properties
index 708d4fcef48b8f142d2fa264525c8aa4b117763d..2c75c8c2ca3e66a49b8c5ddae23db2dc6571a051 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_bg.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_bg.properties
@@ -25,8 +25,7 @@ error.password.noauth=\u041F\u0440\u0435\u0434\u0438\u0448\u043D\u0430\u0442\u04
 error.password.nomatch=\u0414\u0432\u0435\u0442\u0435 \u043D\u043E\u0432\u0438 \u043F\u0430\u0440\u043E\u043B\u0438 \u043D\u0435 \u0441\u044A\u0432\u043F\u0430\u0434\u0430\u0442.
 form.address=\u0410\u0434\u0440\u0435\u0441
 form.charset=\u0417\u043D\u0430\u043A\u043E\u0433\u0435\u043D\u0435\u0440\u0430\u0442\u043E\u0440 \u0438\u0437\u043F\u043E\u043B\u0437\u0432\u0430\u043D \u043F\u0440\u0438 \u0438\u0437\u0442\u0435\u0433\u043B\u044F\u043D\u0435
-form.checkPassword=\u0412\u0430\u0448\u0430\u0442\u0430 \u043F\u0430\u0440\u043E\u043B\u0430 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430 \u043F\u043E\u043D\u0435 4 \u0437\u043D\u0430\u043A\u0430 \u0438 \u0434\u0430 \u0432\u043A\u043B\u044E\u0447\u0432\u0430 \u0446\u0438\u0444\u0440\u0438 \u0438 \u0431\u0443\u043A\u0432\u0438.
-form.checkUsername=\u041F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E\u0442\u043E \u0438\u043C\u0435 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430 \u043F\u043E\u043D\u0435 4 \u0437\u043D\u0430\u043A\u0430 \u0438 \u0441\u0430\u043C\u043E \u0431\u0443\u043A\u0432\u0438 \u043E\u0442 \u0410 \u0434\u043E \u042F (\u0431\u0435\u0437 \u0443\u043C\u043B\u0430\u0443\u0442), \u043A\u0430\u043A\u0442\u043E \u0438 \u0446\u0438\u0444\u0440\u0438 \u043E\u0442 0 \u0434\u043E 9. \u0414\u043E\u043F\u044A\u043B\u043D\u0438\u0442\u0435\u043B\u043D\u043E, \u043C\u043E\u0436\u0435\u0442\u0435 \u0434\u0430 \u0438\u0437\u043F\u043E\u043B\u0437\u0432\u0430\u0442\u0435 . _ \u0438 -.
+form.checkUsername=\u041F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0441\u043A\u043E\u0442\u043E \u0438\u043C\u0435 \u0442\u0440\u044F\u0431\u0432\u0430 \u0434\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430 \u043F\u043E\u043D\u0435 4 \u0437\u043D\u0430\u043A\u0430 \u0438 \u0441\u0430\u043C\u043E \u0431\u0443\u043A\u0432\u0438 \u043E\u0442 \u0410 \u0434\u043E \u042F (\u0431\u0435\u0437 \u0443\u043C\u043B\u0430\u0443\u0442), \u043A\u0430\u043A\u0442\u043E \u0438 \u0446\u0438\u0444\u0440\u0438 \u043E\u0442 0 \u0434\u043E 9. \u0414\u043E\u043F\u044A\u043B\u043D\u0438\u0442\u0435\u043B\u043D\u043E, \u043C\u043E\u0436\u0435\u0442\u0435 \u0434\u0430 \u0438\u0437\u043F\u043E\u043B\u0437\u0432\u0430\u0442\u0435 . @ _ \u0438 -.
 form.description=\u041C\u043E\u043B\u044F, \u043D\u0430\u043F\u0438\u0448\u0435\u0442\u0435 \u0432\u0430\u0448\u0438\u0442\u0435 \u043B\u0438\u0447\u043D\u0438 \u0434\u0430\u043D\u043D\u0438 \u0432\u044A\u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0430 \u043F\u043E-\u0434\u043E\u043B\u0443. \u0421 \u043F\u043E\u043C\u043E\u0449\u0430 \u043D\u0430 \u043A\u0443\u0442\u0438\u0438\u0442\u0435 \u0437\u0430 \u043E\u0442\u043C\u044F\u0442\u0430\u043D\u0435, \u043C\u043E\u0436\u0435\u0442\u0435 \u0434\u0430 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u0435 \u043A\u043E\u0438 \u0432\u043F\u0438\u0441\u0432\u0430\u043D\u0438\u044F \u0449\u0435 \u0441\u0435 \u043F\u043E\u044F\u0432\u044F\u0432\u0430\u0442 \u043D\u0430 \u0432\u0430\u0448\u0430\u0442\u0430 \u0432\u0438\u0437\u0438\u0442\u043D\u0430 \u043A\u0430\u0440\u0442\u0438\u0447\u043A\u0430.
 form.email=\u0418-\u043C\u0435\u0439\u043B \u0430\u0434\u0440\u0435\u0441
 form.fields=\u0418\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u0432\u043F\u0438\u0441\u0432\u0430\u043D\u0438\u044F
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_cs.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_cs.properties
index ea7d8c7f0b173927a7f7c5615aace1fea5261fa7..d74b60be7a53fbc6e28478f68331ad3c26b560ac 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_cs.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_cs.properties
@@ -13,8 +13,7 @@ error.password.noauth=Va\u0161e star\u00E9 heslo bylo zad\u00E1no chybn\u011B.
 error.password.nomatch=Nov\u00E1 hesla jsou r\u016Fzn\u00E1.
 form.address=Adresa
 form.charset=K\u00F3dovac\u00ED mapa pro stahov\u00E1n\u00ED
-form.checkPassword=Heslo mus\u00ED obsahovat alespo\u0148 4 znaky a mus\u00ED obsahovat p\u00EDsmena a \u010D\u00EDsla.
-form.checkUsername=U\u017Eivatelsk\u00E9 jm\u00E9no mus\u00ED obsahovat alespo\u0148 4 znaky od a do z (bez diakritiky) nebo \u010D\u00EDsla od 0 do 9. D\u00E1le m\u016F\u017Eete pou\u017E\u00EDvat . _ a  -.
+form.checkUsername=U\u017Eivatelsk\u00E9 jm\u00E9no mus\u00ED obsahovat alespo\u0148 4 znaky od a do z (bez diakritiky) nebo \u010D\u00EDsla od 0 do 9. D\u00E1le m\u016F\u017Eete pou\u017E\u00EDvat . @ _ a  -.
 form.email=E-mailov\u00E1 adresa
 form.fields=Vybrat polo\u017Eky
 form.fontsize=Velikost fontu
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_da.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_da.properties
index 3107f030e7f29014cf2faa529fded91e4805d8a7..3ce5a7dd5d540a2b53679a4480b5893aea3b099f 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_da.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_da.properties
@@ -13,8 +13,7 @@ error.password.noauth=Dit nuv\u00E6rende kodeord er ikke korrekt.
 error.password.nomatch=De to nye kodeord er ikke ens
 form.address=Adresse
 form.charset=Tegns\u00E6t benyttet i download
-form.checkPassword=Kodeord skal indeholde mindst 4 tegn og inkludere b\u00E5de tal og bogstaver.
-form.checkUsername=Brugernavnet skal v\u00E6re mindst 4 tegn og m\u00E5 kun indeholder bogstaver fra a-z og tal. Dog m\u00E5 du bruge punktum, understregning og bindestreg (._-).
+form.checkUsername=Brugernavnet skal v\u00E6re mindst 4 tegn og m\u00E5 kun indeholder bogstaver fra a-z og tal. Dog m\u00E5 du bruge punktum, understregning og bindestreg (.@_-).
 form.fields=V\u00E6lg felter
 form.fontsize=Skriftst\u00F8rrelse
 form.fontsize.large=Stor
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties
index 3605165cd62410791a4bc11636d4b483d1bec561..e82479fa7a62af128242166df11f106aa8fc92f9 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties
@@ -23,15 +23,15 @@ error.change.email.time=Dieser Aktivierungs-Link hat eine G\u00FCltigkeitsdauer
 error.change.email.unexpected=Ihre E-Mail Adresse konnte nicht ge\u00C4ndert werden. Ein unerwarteter Fehler ist aufgetreten.
 error.no.props.found=Es wurden keine Properties f\u00FCr diesen Benutzer gefunden
 error.password.empty=Geben Sie Ihr bisheriges Passwort an
+error.password.invalid=Das Password ist nicht g\u00FCltig.{0}
 error.password.noauth=Ihr bisheriges Passwort ist nicht korrekt
 error.password.nomatch=Die beiden neuen Passw\u00F6rter stimmen nicht \u00FCberein.
 error.user.logged.in=Diese \u00C4nderung kann nicht vorgenommen werden da der Benutzer {0} zur Zeit eingeloggt ist. Warten Sie bis der Benutzer sich ausloggt und versuchen Sie es erneut. 
+error.username.invalid={0}
 extlink=Externer Link zur Visitenkarte
 form.address=Adresse
 form.charset=Zeichensatz f\u00FCr Download
-form.checkPassword=Das Passwort muss mindestens 4 Zeichen haben. Verwenden Sie dabei sowohl Ziffern als auch Buchstaben.
-form.checkPassword.history=Sie d\u00FCrfen nicht ein Passwort dass Sie schon hatten wieder verwenden.
-form.checkUsername=Der Benutzername muss mindestens 4 Zeichen lang sein und darf nur Buchstaben von a bis z (keine Umlaute, keine Grossbuchstaben) und Ziffern von 0 bis 9 enthalten. Zus\u00E4tzlich sind die Sonderzeichen . _  und - erlaubt.
+form.checkUsername=Der Benutzername muss mindestens 4 Zeichen lang sein und darf nur Buchstaben von a bis z (keine Umlaute, keine Grossbuchstaben) und Ziffern von 0 bis 9 enthalten. Zus\u00E4tzlich sind die Sonderzeichen . @ _  und - erlaubt.
 form.description=Geben Sie im untenstehenden Formular Ihre pers\u00F6nlichen Daten an. Unter "Meine Visitenkarte" bestimmen Sie mit Hilfe der Check-Boxen welche Eintr\u00E4ge auf Ihrer Visitenkarte erscheinen sollen. Dort finden Sie auch die Vorschau.
 form.email=E-Mail
 form.fields=Auswahl der Eintr\u00E4ge
@@ -49,6 +49,7 @@ form.organisations=Organisationen
 form.password.new1=Neues OpenOLAT-Passwort
 form.password.new2=OLAT-Passwort best\u00E4tigen
 form.password.old=Bisheriges OpenOLAT-Passwort
+form.password.validation.rules=Das neue Password muss folgende Kriterien erf\u00FCllen:{0}
 form.please.enter.new=Geben Sie bitte Ihr neues OpenOLAT-Passwort ein.
 form.please.enter.old=Geben Sie bitte Ihr bisheriges OpenOLAT-Passwort ein.
 form.text=Pers\u00F6nlicher Text
@@ -93,12 +94,13 @@ propdelete.yesno.title=Sind Sie sicher?
 pwdav.access_data=<h4>Zugangsdaten</h4>
 pwdav.description=WebDAV erm\u00F6glicht Ihnen einen einfachen Dateitransfer von Ihrem Rechner zu OpenOLAT-Ordnern, wobei Sie mit Drag und Drop nebst einzelnen Dateien auch ganze Verzeichnisse in OpenOLAT-Ordner kopieren k\u00F6nnen. Um WebDAV zu nutzen, m\u00FCssen Sie auf Ihrem Computer ein Netzlaufwerk mit untenstehender Adresse anlegen\: 
 pwdav.password=WebDAV-Passwort
-pwdav.password.change=Passwort \u00C4ndern
+pwdav.password.change=Passwort \u00E4ndern
 pwdav.password.confirm=WebDAV-Passwort best\u00E4tigen
 pwdav.password.failed=Ihr neues WebDAV Passwort wurde nicht gespeichert. Ein unerwarteter Fehler ist aufgetreten. 
 pwdav.password.new=Passwort einrichten
 pwdav.password.not_set=<i>WebDAV Passwort nicht eingerichtet</i>
 pwdav.password.placeholder=<i>verwenden Sie Ihr OpenOLAT Passwort f\u00FCr den WebDAV Zugang</i>
+pwdav.password.rules=$\:form.password.validation.rules
 pwdav.password.set=******* (Passwort verschl\u00FCsselt)
 pwdav.password.successful=Ihr neues WebDAV Passwort wurde erfolgreich gespeichert. Es ist ab sofort aktiv.
 pwdav.title=WebDAV Zugang
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_el.properties
index b4f764cc2aae6bae4c6a82e4d26ec40a831cb47d..1851674e917a8d1c5520e8994bf259394b7cfead 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_el.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_el.properties
@@ -25,8 +25,7 @@ error.password.noauth=\u039F \u03C0\u03B1\u03BB\u03B1\u03B9\u03CC\u03C2 \u03BA\u
 error.password.nomatch=\u039F\u03B9 \u03B4\u03CD\u03BF \u03BD\u03AD\u03BF\u03B9 \u03BA\u03C9\u03B4\u03B9\u03BA\u03BF\u03AF \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03B4\u03B5\u03BD \u03C4\u03B1\u03B9\u03C1\u03B9\u03AC\u03B6\u03BF\u03C5\u03BD.
 form.address=\u0394\u03B9\u03B5\u03CD\u03B8\u03C5\u03BD\u03C3\u03B7
 form.charset=\u03A3\u03CD\u03BD\u03BF\u03BB\u03BF \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1\u03C9\u03BD \u03C0\u03BF\u03C5 \u03C7\u03C1\u03B7\u03C3\u03B9\u03BC\u03BF\u03C0\u03BF\u03B9\u03B5\u03AF\u03C4\u03B1\u03B9 \u03BA\u03B1\u03C4\u03AC \u03C4\u03B7 \u03BB\u03AE\u03C8\u03B7
-form.checkPassword=\u039F \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03C0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7\u03C2 \u03C0\u03C1\u03AD\u03C0\u03B5\u03B9 \u03BD\u03B1 \u03C0\u03B5\u03C1\u03B9\u03AD\u03C7\u03B5\u03B9 \u03C4\u03BF\u03C5\u03BB\u03AC\u03C7\u03B9\u03C3\u03C4\u03BF\u03BD 4 \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1\u03B5\u03C2 \u03BC\u03B5 \u03BB\u03B1\u03C4\u03B9\u03BD\u03B9\u03BA\u03AC \u03B3\u03C1\u03AC\u03BC\u03BC\u03B1\u03C4\u03B1 \u03AE \u03C8\u03B7\u03C6\u03AF\u03B1.
-form.checkUsername=\u03A4\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03C0\u03C1\u03AD\u03C0\u03B5\u03B9 \u03BD \u03C0\u03B5\u03C1\u03B9\u03AD\u03C7\u03B5\u03B9 \u03C4\u03BF\u03C5\u03BB\u03AC\u03C7\u03B9\u03C3\u03C4\u03BF\u03BD 4 \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1\u03B5\u03C2 \u03BA\u03B1\u03B9 \u03BC\u03CC\u03BD\u03BF \u03B3\u03C1\u03AC\u03BC\u03BC\u03B1\u03C4 \u03B1\u03C0\u03CC \u03C4\u03BF a \u03AD\u03C9\u03C2 \u03C4\u03BF z (\u03C7\u03C9\u03C1\u03AF\u03C2 \u03C3\u03B7\u03BC\u03B5\u03AF\u03B1 \u03C3\u03C4\u03AF\u03BE\u03B7\u03C2) \u03BA\u03B1\u03B8\u03CE\u03C2 \u03BA\u03B1\u03B9 \u03C8\u03B7\u03C6\u03AF\u03B1 \u03B1\u03C0\u03CC \u03C4\u03BF 0 \u03AD\u03C9\u03C2 \u03C4\u03BF 9. \u0395\u03C0\u03B9\u03C0\u03BB\u03AD\u03BF\u03BD \u03BC\u03C0\u03BF\u03C1\u03B5\u03AF\u03C4\u03B5 \u03BD\u03B1 \u03C7\u03C1\u03B7\u03C3\u03B9\u03BC\u03BF\u03C0\u03BF\u03B9\u03AE\u03C3\u03B5\u03C4\u03B5 \u03C4\u03BF\u03C5\u03C2 \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1\u03B5\u03C2 . _ \u03BA\u03B1\u03B9 -.
+form.checkUsername=\u03A4\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03C0\u03C1\u03AD\u03C0\u03B5\u03B9 \u03BD \u03C0\u03B5\u03C1\u03B9\u03AD\u03C7\u03B5\u03B9 \u03C4\u03BF\u03C5\u03BB\u03AC\u03C7\u03B9\u03C3\u03C4\u03BF\u03BD 4 \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1\u03B5\u03C2 \u03BA\u03B1\u03B9 \u03BC\u03CC\u03BD\u03BF \u03B3\u03C1\u03AC\u03BC\u03BC\u03B1\u03C4 \u03B1\u03C0\u03CC \u03C4\u03BF a \u03AD\u03C9\u03C2 \u03C4\u03BF z (\u03C7\u03C9\u03C1\u03AF\u03C2 \u03C3\u03B7\u03BC\u03B5\u03AF\u03B1 \u03C3\u03C4\u03AF\u03BE\u03B7\u03C2) \u03BA\u03B1\u03B8\u03CE\u03C2 \u03BA\u03B1\u03B9 \u03C8\u03B7\u03C6\u03AF\u03B1 \u03B1\u03C0\u03CC \u03C4\u03BF 0 \u03AD\u03C9\u03C2 \u03C4\u03BF 9. \u0395\u03C0\u03B9\u03C0\u03BB\u03AD\u03BF\u03BD \u03BC\u03C0\u03BF\u03C1\u03B5\u03AF\u03C4\u03B5 \u03BD\u03B1 \u03C7\u03C1\u03B7\u03C3\u03B9\u03BC\u03BF\u03C0\u03BF\u03B9\u03AE\u03C3\u03B5\u03C4\u03B5 \u03C4\u03BF\u03C5\u03C2 \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1\u03B5\u03C2 . @ _ \u03BA\u03B1\u03B9 -.
 form.description=\u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03B5\u03B9\u03C3\u03AC\u03B3\u03B5\u03C4\u03B5 \u03C4\u03B1 \u03C0\u03C1\u03BF\u03C3\u03C9\u03C0\u03B9\u03BA\u03AC \u03C3\u03B1\u03C2 \u03C3\u03C4\u03BF\u03B9\u03C7\u03B5\u03AF\u03B1 \u03C3\u03C4\u03B7\u03BD \u03C0\u03B1\u03C1\u03B1\u03BA\u03AC\u03C4\u03C9 \u03C6\u03CC\u03C1\u03BC\u03B1. \u039C\u03C0\u03BF\u03C1\u03B5\u03AF\u03C4\u03B5 \u03BD\u03B1 \u03BF\u03C1\u03AF\u03C3\u03B5\u03C4\u03B5 \u03C4\u03B9\u03C2 \u03BA\u03B1\u03C4\u03B1\u03C7\u03C9\u03C1\u03AE\u03C3\u03B5\u03B9\u03C2 \u03C0\u03BF\u03C5 \u03B5\u03BC\u03C6\u03B1\u03BD\u03AF\u03B6\u03BF\u03BD\u03C4\u03B1\u03B9 \u03C3\u03C4\u03B7\u03BD \u03BA\u03AC\u03C1\u03C4\u03B1 \u03B5\u03C0\u03B9\u03C3\u03BA\u03AD\u03C0\u03C4\u03B7 \u03C7\u03C1\u03B7\u03C3\u03B9\u03BC\u03BF\u03C0\u03BF\u03B9\u03CE\u03BD\u03C4\u03B1\u03C2 \u03C4\u03B1 \u03BA\u03BF\u03C5\u03C4\u03B9\u03AC \u03B5\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE\u03C2.
 form.email=\u0394\u03B9\u03B5\u03CD\u03B8\u03C5\u03BD\u03C3\u03B7 E-mail
 form.fields=\u0395\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE \u03BA\u03B1\u03C1\u03B1\u03C7\u03C9\u03C1\u03AE\u03C3\u03B5\u03C9\u03BD
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties
index 37d2e15cf45b7a8f16e8e748e1944b0e369d6914..00f65d75eb30c63bfa2177ebbb06d0e3b6e723e9 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties
@@ -23,15 +23,15 @@ error.change.email.time=This activating link can only be used for {0} hrs and is
 error.change.email.unexpected=Your E-mail could not be changed. An unexpected server error occurred.
 error.no.props.found=No properties found for this user
 error.password.empty=Please indicate your previous password
+error.password.invalid=The password is not valid.{0}
 error.password.noauth=Your previous password is inaccurate
 error.password.nomatch=The two new passwords do not match.
 error.user.logged.in=This change can not be made as the user {0} is currently logged in. Please wait until the user has logged out and try it again. 
+error.username.invalid={0}
 extlink=External link to visiting card
 form.address=Address
 form.charset=Character set used in download
-form.checkPassword=Your password must contain at least 4 characters and include digits and letters.
-form.checkPassword.history=You cannot use a password you already used in the past.
-form.checkUsername=User names have to contain at least 4 characters and only letters from a to z (no umlaut or capital letters) as well as digits from 0 to 9. Additionally you may use . _ and -.
+form.checkUsername=User names have to contain at least 4 characters and only letters from a to z (no umlaut or capital letters) as well as digits from 0 to 9. Additionally you may use . @ _ and -.
 form.description=Please indicate your personal data in the form below. By means of check boxes you can determine the entries that should appear on your visiting card.
 form.email=E-mail
 form.fields=Selection of entries
@@ -49,6 +49,7 @@ form.organisations=Organisations
 form.password.new1=New OpenOLAT password
 form.password.new2=Confirm OpenOLAT password
 form.password.old=Old OpenOLAT password
+form.password.validation.rules=The new password must meet the following criteria:{0}
 form.please.enter.new=Please enter your new OpenOLAT password.
 form.please.enter.old=Please enter your old OpenOLAT password.
 form.text=Personal text
@@ -99,6 +100,7 @@ pwdav.password.failed=Your new WebDAV password could not be saved. An unexpected
 pwdav.password.new=Set password
 pwdav.password.not_set=<i>WebDAV password not set</i>
 pwdav.password.placeholder=<i>Please use your OpenOLAT password to access WebDAV</i>
+pwdav.password.rules=$\:form.password.validation.rules
 pwdav.password.set=******* (password encoded)
 pwdav.password.successful=Your new WebDAV password has been saved successfully. It is valid from now on.
 pwdav.title=WebDAV access
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_es.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_es.properties
index ae7dd65a8128803e53866cce60b81960bfc35460..718185f3a03b572285da1f70b531a9d0b5890ef0 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_es.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_es.properties
@@ -25,8 +25,7 @@ error.password.noauth=Tu anterior contrase\u00F1a no es correcta.
 error.password.nomatch=Las dos contrase\u00F1as nuevas no coinciden.
 form.address=Direcci\u00F3n
 form.charset=Conjunto de caracteres utilizados en la descarga
-form.checkPassword=La contrase\u00F1a debe contener al menos 4 caracteres e incluir d\u00EDgitos y letras.
-form.checkUsername=El nombre de usuario debe contener al menos 4 caracteres y s\u00F3lo letras de la 'a' a la 'z' (sin di\u00E9resis ni acentos) asi como n\u00FAmeros de 0 a 9. Adiccionalmente puedes utilizar . _ y -. 
+form.checkUsername=El nombre de usuario debe contener al menos 4 caracteres y s\u00F3lo letras de la 'a' a la 'z' (sin di\u00E9resis ni acentos) asi como n\u00FAmeros de 0 a 9. Adiccionalmente puedes utilizar . @ _ y -. 
 form.description=Por favor, indique sus datos personales en el formulario de abajo. Por medio de las casillas de verificaci\u00F3n se puede determinar las entradas que deben aparecer en su tarjeta de visita.
 form.email=E-mail
 form.fields=Seleccionar entradas
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_fa.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_fa.properties
index 6e750912c15d89f9d059d12bce22f70dcbec2de0..341898400db89a9edfb7a4db577af50f40192073 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_fa.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_fa.properties
@@ -13,7 +13,6 @@ error.password.noauth=\u06A9\u0644\u0645\u0647 \u0639\u0628\u0648\u0631 \u0642\u
 error.password.nomatch=\u062F\u0648 \u06A9\u0644\u0645\u0647 \u0639\u0628\u0648\u0631 \u062C\u062F\u06CC\u062F \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F
 form.address=\u0622\u062F\u0631\u0633
 form.charset=Character set used in download
-form.checkPassword=\u06A9\u0644\u0645\u0647 \u0639\u0628\u0648\u0631 \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 \u0634\u0627\u0645\u0644 4 \u06A9\u0627\u0631\u0627\u06A9\u062A\u0631\u0645\u062A\u0634\u06A9\u0644 \u0627\u0632 \u062D\u0631\u0648\u0641 \u0648 \u0627\u0639\u062F\u0627\u062F \u0628\u0627\u0634\u062F
 form.fields=\u0627\u0646\u062A\u062E\u0627\u0628 \u0645\u062F\u062E\u0644
 form.fontsize=\u0627\u0646\u062F\u0627\u0632\u0647 \u0641\u0648\u0646\u062A
 form.fontsize.large=\u0628\u0632\u0631\u06AF
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_fr.properties
index 97942be7e32100b78ebdc1a55220752959a2ae2b..94b1db1a0d2a6161745a8d39ea22bee67fecc409 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_fr.properties
@@ -29,9 +29,7 @@ error.user.logged.in=Ce changement ne peut pas \u00EAtre effectu\u00E9e pour l'i
 extlink=Lien externe vers la carte de visite
 form.address=Adresse
 form.charset=Jeu de caract\u00E8res pour t\u00E9l\u00E9chargement
-form.checkPassword=Le mot de passe doit contenir au moins quatre caract\u00E8res. Utilisez des lettres ET des chiffres.
-form.checkPassword.history=Vous ne pouvez pas r\u00E9utiliser un mot de passe que vous avez d\u00E9j\u00E0 utilis\u00E9 par le pass\u00E9.
-form.checkUsername=Le nom d'utilisateur doit \u00EAtre compos\u00E9 d'au moins 4 caract\u00E8res et ne doit contenir que des lettres de A \u00E0 Z (sans accents) et des chiffres de 0 \u00E0 9. En plus les caract\u00E8res sp\u00E9ciaux . _ et - sont permis.
+form.checkUsername=Le nom d'utilisateur doit \u00EAtre compos\u00E9 d'au moins 4 caract\u00E8res et ne doit contenir que des lettres de A \u00E0 Z (sans accents) et des chiffres de 0 \u00E0 9. En plus les caract\u00E8res sp\u00E9ciaux . @ _ et - sont permis.
 form.description=Indiquez vos donn\u00E9es personnelles dans le formulaire ci-dessous. Vous pouvez d\u00E9cider laquelle des entr\u00E9es sera visible sur votre carte de visite gr\u00E2ce au bo\u00EEtes \u00E0 cocher. 
 form.email=E-mail
 form.fields=S\u00E9lection des entr\u00E9es
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_it.properties
index c3a0cf09cb8059b2b1b8057bc4f5b12ea359184f..165626953070ed47191d57eeacde829b48d866f3 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_it.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_it.properties
@@ -28,8 +28,7 @@ error.user.logged.in=Questo cambiamento non pu\u00F2 essere effettuato poich\u00
 extlink=Link esterno al biglietto da visita
 form.address=Indirizzo
 form.charset=Set di caratteri per lo scaricamento
-form.checkPassword=La password deve contenere almeno 4 segni. Utilizzi sia cifre che lettere.
-form.checkUsername=Il nome d'utente deve contenere almeno 4 segni e consistere solo di lettere dalla a alla z (senza '\u00E4', '\u00F6' ecc.) e cifre da 0 a 9. In aggiunta sono permessi i segni speciali . _  e -.
+form.checkUsername=Il nome d'utente deve contenere almeno 4 segni e consistere solo di lettere dalla a alla z (senza '\u00E4', '\u00F6' ecc.) e cifre da 0 a 9. In aggiunta sono permessi i segni speciali . @ _  e -.
 form.description=Indichi nel formulario sottostante i Suoi dati personali, p.f. Utilizzando le caselle a selezione pu\u00F2 stabilire quali informazioni saranno visibili sul Suo biglietto da visita.
 form.email=E-mail
 form.fields=Selezione delle entrate
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_jp.properties
index 26d2433e32009d8738fbd2c16f5e83cd1be33154..5e20a56cf3d175b4d3bf789fbe62925cd2b5f934 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_jp.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_jp.properties
@@ -19,8 +19,6 @@ error.password.noauth=\u3042\u306A\u305F\u306E\u524D\u306E\u30D1\u30B9\u30EF\u30
 error.password.nomatch=2\u3064\u306E\u65B0\u3057\u3044\u30D1\u30B9\u30EF\u30FC\u30C9\u304C\u5408\u81F4\u3057\u307E\u305B\u3093\u3002
 form.address=\u4F4F\u6240
 form.charset=\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u306B\u4F7F\u7528\u3059\u308B\u6587\u5B57\u30BB\u30C3\u30C8
-form.checkPassword=\u3042\u306A\u305F\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u3001\u6570\u5B57\u304A\u3088\u3073\u6587\u5B57\u3092\u542B\u3080\u3001\u5C11\u306A\u304F\u3068\u30824\u6587\u5B57\u306B\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002
-form.checkUsername=\u30E6\u30FC\u30B6\u540D\u306B\u306F\u5C11\u306A\u304F\u3068\u3082\u534A\u89D24\u6587\u5B57\u3092\u542B\u307F\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u6570\u5B570\u304B\u30899\u304A\u3088\u3073A\u304B\u3089Z (\u30A6\u30E0\u30E9\u30A6\u30C8\u306A\u3057) \u306E\u6587\u5B57\u306E\u307F\u4F7F\u7528\u3067\u304D\u307E\u3059\u3002\u307E\u305F\u3001\u3042\u306A\u305F\u306F\u300C.\u300D\u300C_\u300D\u300C-\u300D\u3092\u4F7F\u7528\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002
 form.description=\u4E0B\u8A18\u306E\u30D5\u30A9\u30FC\u30E0\u306B\u3001\u3042\u306A\u305F\u306E\u500B\u4EBA\u30C7\u30FC\u30BF\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30C1\u30A7\u30C3\u30AF\u30DC\u30C3\u30AF\u30B9\u3092\u4F7F\u7528\u3059\u308B\u3053\u3068\u3067\u3001\u3042\u306A\u305F\u306E\u30D3\u30B8\u30C6\u30A3\u30F3\u30B0\u30AB\u30FC\u30C9\u306B\u8868\u793A\u3059\u308B\u30A8\u30F3\u30C8\u30EA\u3092\u6307\u5B9A\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002
 form.email=E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9
 form.fields=\u30A8\u30F3\u30C8\u30EA\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_lt.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_lt.properties
index e72ee8fc1a5d183c26dd7930c7ec256496095cf5..c62f0b44b19d664bb614ee9da09336dea2febdb9 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_lt.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_lt.properties
@@ -13,8 +13,7 @@ error.password.noauth=J\u016Bs\u0173 senas slapta\u017Eodis n\u0117ra teisingas.
 error.password.nomatch=Du nauji slapta\u017Eod\u017Eiai neatitinka.
 form.address=Adresas
 form.charset=\u017Denkl\u0173 rinkinys naudojamas siun\u010Diantis
-form.checkPassword=Slapta\u017Eod\u012F turi sudaryti ma\u017Eiausiai 4 simboliai \u012Ftraukiant skai\u010Dius ir raides.
-form.checkUsername=Vartotojo vard\u0105 turi sudaryti ma\u017Eiausiai 4 simboliai, raid\u0117s\: a-z (be umliaut\u0173), skai\u010Diai\: 0-9. J\u016Bs galite naudoti . _ ir -.
+form.checkUsername=Vartotojo vard\u0105 turi sudaryti ma\u017Eiausiai 4 simboliai, raid\u0117s\: a-z (be umliaut\u0173), skai\u010Diai\: 0-9. J\u016Bs galite naudoti . @ _ ir -.
 form.fields=Pa\u017Eym\u0117kite \u012Fvestis
 form.fontsize=\u0160rifto dydis
 form.fontsize.large=Didelis
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_nl_NL.properties
index 64d60109315d16fe7ce1ad7c4b8ec1749963b04e..50459941002c01265ab67705e59e63a1e9ff87a1 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_nl_NL.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_nl_NL.properties
@@ -25,8 +25,6 @@ error.password.noauth=Uw vorige wachtwoord is niet correct
 error.password.nomatch=De twee nieuwe wachtwoorden komen niet overeen.
 form.address=Adres
 form.charset=Tekenset gebruikt bij download
-form.checkPassword=Uw wachtwoord moet minstens 4 tekens bevatten en moet bestaan uit cijfers en letters.
-form.checkUsername=De gebruikersnaam moet op zijn minst 4 tekens bevatten en moet zowel bestaan uit letters van A tot Z  (zonder umlautsteken) als uit cijfers van 0 tot 9. Ook mag u ._ en -. gebruiken.
 form.description=Gelieve uw persoonlijke data in te geven in het onderstaande formulier. Doormiddel van de check-boxen kunt u bepalen welke gegevens moeten verschijnen op uw visitekaartje.
 form.email=E-mailadres
 form.fields=Kies gegevens
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_pl.properties
index a4893bac1e5ba99c72c1c7069971899d0eed9169..78e57a36ae969d3f3e3302b9f0350bc4857d0a90 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_pl.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_pl.properties
@@ -25,8 +25,7 @@ error.password.noauth=Stare has\u0142o jest nieprawid\u0142owe
 error.password.nomatch=Nowe has\u0142a nie pasuj\u0105
 form.address=Adres
 form.charset=Zbi\u00F3r znak\u00F3w u\u017Cywany podczas pobierania plik\u00F3w
-form.checkPassword=Has\u0142o musi zawiera\u0107 co najmniej 4 znaki, w tym litery i cyfry.
-form.checkUsername=Nazwa u\u017Cytkownika musi zawiera\u0107 co najmniej 4 znaki- litery od a do z i cyfry od 0 do 9. Dodatkowo mo\u017Cesz u\u017Cy\u0107 . _ i -
+form.checkUsername=Nazwa u\u017Cytkownika musi zawiera\u0107 co najmniej 4 znaki- litery od a do z i cyfry od 0 do 9. Dodatkowo mo\u017Cesz u\u017Cy\u0107 . @ _ i -
 form.description=Uzupe\u0142nij swoje dane osobowe w formularzu poni\u017Cej. Za pomoc\u0105 pola wyboru mo\u017Cna okre\u015Bli\u0107 pozycje, kt\u00F3re powinny znajdowa\u0107 si\u0119 na Twojej wizyt\u00F3wce.
 form.email=Adres e-mail
 form.fields=Wybierz wpisy
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_pt_BR.properties
index 60a036035dbec65cdf4f4e5ba9ea4812dcb0fdc8..9d646c60080d42847433888afe29a8b7139e9ae3 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_pt_BR.properties
@@ -29,9 +29,7 @@ error.user.logged.in=Esta mudan\u00E7a n\u00E3o pode ser feita pois o usu\u00E1r
 extlink=Link externo para cart\u00E3o de visita
 form.address=Endere\u00E7o
 form.charset=Cadeia de caracteres utilizada no download
-form.checkPassword=A senha deve conter pelo menos 4 caracteres e incluir d\u00EDgitos e letras
-form.checkPassword.history=Voc\u00EA n\u00E3o pode usar uma senha que j\u00E1 usou no passado.
-form.checkUsername=O nome de usu\u00E1rio tem que ter pelo menos 4 caracteres e somente letras de a a z (min\u00FAsculas) bem como d\u00EDgitos de 0 a 9. Adicionalmente voc\u00EA pode usar . _ e -.
+form.checkUsername=O nome de usu\u00E1rio tem que ter pelo menos 4 caracteres e somente letras de a a z (min\u00FAsculas) bem como d\u00EDgitos de 0 a 9. Adicionalmente voc\u00EA pode usar . @ _ e -.
 form.description=Indique os seus dados pessoais no formul\u00E1rio abaixo. Atrav\u00E9s das lacunas voc\u00EA pode determinar as entradas que devem aparecer no seu cart\u00E3o de visita.
 form.email=Endere\u00E7o de E-mail
 form.fields=Selecionar itens
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_pt_PT.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_pt_PT.properties
index 51a44bce563c433c1b08231ebd7ac87900a06a57..3942be6e81dec9b0e6c0dc8932468e6fc3adee13 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_pt_PT.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_pt_PT.properties
@@ -13,8 +13,7 @@ error.password.noauth=Sua senha antiga est\u00E1 incorreta
 error.password.nomatch=As duas novas senhas n\u00E3o coincidem
 form.address=Endere\u00E7o
 form.charset=Cadeia de caracteres utilizada no download
-form.checkPassword=A senha deve conter pelo menos 4 caracteres e incluir d\u00EDgitos e letras
-form.checkUsername=O nome de usu\u00E1rio tem que ter pelo menos 4 caracteres e somente letras de a a z (min\u00FAsculas) bem como d\u00EDgitos de 0 a 9. Adicionalmente voc\u00EA pode usar . _ e -.
+form.checkUsername=O nome de usu\u00E1rio tem que ter pelo menos 4 caracteres e somente letras de a a z (min\u00FAsculas) bem como d\u00EDgitos de 0 a 9. Adicionalmente voc\u00EA pode usar . @ _ e -.
 form.fields=Selecionar itens
 form.fontsize=Tamanho de fonte
 form.fontsize.large=Grande
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_ru.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_ru.properties
index 69c104f9b9974189f1e965188d20970770d4d825..e6773780a238102c5f53ed77c256aa7f03c35226 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_ru.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_ru.properties
@@ -25,8 +25,7 @@ error.password.noauth=\u0412\u0430\u0448 \u0441\u0442\u0430\u0440\u044B\u0439 \u
 error.password.nomatch=\u041E\u0431\u0430 \u043D\u043E\u0432\u044B\u0445 \u043F\u0430\u0440\u043E\u043B\u044F \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u044E\u0442. 
 form.address=\u0410\u0434\u0440\u0435\u0441
 form.charset=\u041A\u043E\u0434\u0438\u0440\u043E\u0432\u043A\u0430 \u0434\u043B\u044F \u0441\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u044F
-form.checkPassword=\u041F\u0430\u0440\u043E\u043B\u044C \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0441\u0442\u043E\u044F\u0442\u044C \u043A\u0430\u043A \u043C\u0438\u043D\u0438\u043C\u0443\u043C \u0438\u0437 4-\u0445 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432. \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 \u043F\u0440\u0438 \u044D\u0442\u043E\u043C \u043A\u0430\u043A \u0447\u0438\u0441\u043B\u0430, \u0442\u0430\u043A \u0438 \u0431\u0443\u043A\u0432\u044B.
-form.checkUsername=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0434\u043E\u043B\u0436\u043D\u043E \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u043A\u0430\u043A \u043C\u0438\u043D\u0438\u043C\u0443\u043C 4 \u0441\u0438\u043C\u0432\u043E\u043B\u0430 \u0438 \u0441\u043E\u0441\u0442\u043E\u044F\u0442\u044C \u0438\u0437 \u0431\u0443\u043A\u0432 \u043E\u0442 \u0430 \u0434\u043E \u044F (\u0431\u0435\u0437 \u0437\u0430\u0433\u043B\u0430\u0432\u043D\u044B\u0445 \u0431\u0443\u043A\u0432) \u0438 \u0446\u0438\u0444\u0440 \u043E\u0442 0 \u0434\u043E 9. \u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u043E \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0435 \u0442\u0430\u043A\u0438\u0445 \u0441\u043F\u0435\u0446\u0438\u0430\u043B\u044C\u043D\u044B\u0445 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432 \u043A\u0430\u043A . _  \u0438 - .
+form.checkUsername=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0434\u043E\u043B\u0436\u043D\u043E \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u043A\u0430\u043A \u043C\u0438\u043D\u0438\u043C\u0443\u043C 4 \u0441\u0438\u043C\u0432\u043E\u043B\u0430 \u0438 \u0441\u043E\u0441\u0442\u043E\u044F\u0442\u044C \u0438\u0437 \u0431\u0443\u043A\u0432 \u043E\u0442 \u0430 \u0434\u043E \u044F (\u0431\u0435\u0437 \u0437\u0430\u0433\u043B\u0430\u0432\u043D\u044B\u0445 \u0431\u0443\u043A\u0432) \u0438 \u0446\u0438\u0444\u0440 \u043E\u0442 0 \u0434\u043E 9. \u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u043E \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0435 \u0442\u0430\u043A\u0438\u0445 \u0441\u043F\u0435\u0446\u0438\u0430\u043B\u044C\u043D\u044B\u0445 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432 \u043A\u0430\u043A . @ _  \u0438 - .
 form.description=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0432 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0444\u043E\u0440\u043C\u0443\u043B\u044F\u0440 \u0412\u0430\u0448\u0438 \u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\u044C\u043D\u044B\u0435 \u0434\u0430\u043D\u043D\u044B\u0435. \u0421 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u043E\u043A\u043E\u0448\u0435\u043A \u0434\u043B\u044F \u0432\u044B\u0431\u043E\u0440\u0430 \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C, \u0447\u0442\u043E \u0434\u043E\u043B\u0436\u043D\u043E \u043F\u043E\u044F\u0432\u0438\u0442\u044C\u0441\u044F \u043D\u0430 \u0412\u0430\u0448\u0435\u0439 \u0432\u0438\u0437\u0438\u0442\u043D\u043E\u0439 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0435.
 form.email=E-mail \u0430\u0434\u0440\u0435\u0441
 form.fields=\u0412\u044B\u0431\u043E\u0440 \u0434\u0430\u043D\u043D\u044B\u0445
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_sq.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_sq.properties
index 597ef8abd3524c6fb24de91e1449b927e34f5a2e..a8149b74918546e9f1f4d7e79d4968c770267581 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_sq.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_sq.properties
@@ -13,8 +13,7 @@ error.password.noauth=Fjal\u00EBkalimi juaj i vjet\u00EBr nuk \u00EBsht\u00EB i
 error.password.nomatch=Dy fjal\u00EBkalimet e reja nuk p\u00EBrputhen.
 form.address=Adresa
 form.charset=karakteret e shfryt\u00EBzuara gjat\u00EB shkarkimit
-form.checkPassword=Fjal\u00EBkalimi duhet t\u00EB p\u00EBrmbaj t\u00EB pakt\u00EBn 4 shkronja dhe t\u00EB p\u00EBrfshij numra dhe shkronja.
-form.checkUsername=Emri i shfryt\u00EBzuesit duhet t\u00EB p\u00EBrmbaj\u00EB s\u00EB paku 4 karaktere dhe shkronja vet\u00EBm prej a deri n\u00EB zh (pa dyshim zanoreje) si dhe numrat prej 0 deri n\u00EB 9. Poashtu ju mund t\u00EB shfryt\u00EBzoni . _ dhe -.
+form.checkUsername=Emri i shfryt\u00EBzuesit duhet t\u00EB p\u00EBrmbaj\u00EB s\u00EB paku 4 karaktere dhe shkronja vet\u00EBm prej a deri n\u00EB zh (pa dyshim zanoreje) si dhe numrat prej 0 deri n\u00EB 9. Poashtu ju mund t\u00EB shfryt\u00EBzoni . @ _ dhe -.
 form.fields=Zgjedh hyrjet
 form.fontsize=Madh\u00EBsia e shkronjave
 form.fontsize.large=T\u00EB m\u00EBdhaja
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_zh_CN.properties
index b2a11128f9734b70c65d3ffc5982f928b55ed699..53ec1e70119d823ae35e569c625e7a7fd2cc4b1f 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_zh_CN.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_zh_CN.properties
@@ -27,8 +27,6 @@ error.user.logged.in=\u7531\u4E8E\u7528\u6237\u5DF2\u767B\u5F55\uFF0C\u4E0D\u80F
 extlink=\u540D\u7247\u7684\u5916\u90E8\u94FE\u63A5
 form.address=\u5730\u5740
 form.charset=\u5728\u4E0B\u8F7D\u4E2D\u7528\u5230\u7684\u5B57\u7B26\u96C6
-form.checkPassword=\u5BC6\u7801\u5FC5\u987B\u5305\u542B\u81F3\u5C114\u4E2A\u5B57\u7B26\uFF0C\u4E14\u5FC5\u987B\u5305\u542B\u5B57\u7B26\u548C\u6570\u5B57\u3002
-form.checkUsername=\u7528\u6237\u540D\u81F3\u5C11\u5305\u542B4\u4E2A\u5B57\u7B26\uFF0C\u4E14\u53EA\u80FD\u662Fa-z\u7684\u5B57\u6BCD\u548C0-9\u7684\u6570\u5B57\u3002\u6B64\u5916\uFF0C\u60A8\u53EF\u4EE5\u4F7F\u7528 . _\u548C -\u3002
 form.description=\u8BF7\u5728\u4E0B\u9762\u7684\u8868\u683C\u4E2D\u8868\u660E\u4F60\u7684\u4E2A\u4EBA\u4FE1\u606F\u3002\u901A\u8FC7\u70B9\u51FB\u590D\u9009\u6846\u4F60\u53EF\u4EE5\u51B3\u5B9A\u8FD9\u4E9B\u6761\u76EE\u662F\u5426\u51FA\u73B0\u5728\u4F60\u7684\u8BBF\u95EE\u5361\u7247\u4E0A\u3002
 form.email=e-mail\u5730\u5740
 form.fields=\u9009\u62E9\u6761\u76EE
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_zh_TW.properties
index bfa0ab7c90071ab5b2c36dedee44b5e3b0a474f5..baa7b355fe0182cf1637087a9a4a22731960d182 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_zh_TW.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_zh_TW.properties
@@ -24,8 +24,7 @@ error.password.noauth=\u60A8\u7684\u820A\u5BC6\u78BC\u4E0D\u6B63\u78BA
 error.password.nomatch=\u9019\u5169\u500B\u65B0\u7684\u5BC6\u78BC\u4E26\u4E0D\u76F8\u7B26\u3002
 form.address=\u5730\u5740
 form.charset=\u4E0B\u8F09\u6642\u4F7F\u7528\u7684\u5B57\u5143\u96C6
-form.checkPassword=\u60A8\u7684\u5BC6\u78BC\u5FC5\u9808\u5305\u542B\u81F3\u5C11 4 \u500B\u5B57\u5143\u4E26\u4E14\u5305\u542B\u6578\u5B57\u548C\u5B57\u6BCD\u3002
-form.checkUsername=\u4F7F\u7528\u8005\u540D\u7A31\u5FC5\u9808\u5305\u542B\u81F3\u5C11 4 \u500B\u5B57\u5143\uFF0C\u4E14\u53EA\u6709\u5F9E A \u5230 Z (\u7121\u8B8A\u97F3) \u7684\u5B57\u6BCD\u4EE5\u53CA\u5F9E 0 \u5230 9 \u7684\u6578\u5B57\u3002\u6B64\u5916\uFF0C\u60A8\u53EF\u4EE5\u4F7F\u7528 . _ \u548C -\u3002
+form.checkUsername=\u4F7F\u7528\u8005\u540D\u7A31\u5FC5\u9808\u5305\u542B\u81F3\u5C11 4 \u500B\u5B57\u5143\uFF0C\u4E14\u53EA\u6709\u5F9E A \u5230 Z (\u7121\u8B8A\u97F3) \u7684\u5B57\u6BCD\u4EE5\u53CA\u5F9E 0 \u5230 9 \u7684\u6578\u5B57\u3002\u6B64\u5916\uFF0C\u60A8\u53EF\u4EE5\u4F7F\u7528 . @ _ \u548C -\u3002
 form.description=\u8ACB\u5728\u4E0B\u5217\u7684\u8868\u55AE\u4E2D\u8F38\u5165\u60A8\u7684\u500B\u4EBA\u8CC7\u6599\u3002\u85C9\u7531\u6838\u9078\u65B9\u584A\u60A8\u53EF\u4EE5\u6C7A\u5B9A\u90A3\u4E9B\u9805\u76EE\u61C9\u8A72\u51FA\u73FE\u5728\u60A8\u7684\u540D\u7247\u4E0A\u3002
 form.email=\u96FB\u5B50\u90F5\u4EF6\u5730\u5740
 form.fields=\u9078\u64C7\u9805\u76EE
diff --git a/src/main/java/org/olat/user/_spring/userContext.xml b/src/main/java/org/olat/user/_spring/userContext.xml
index ea993cc035b2a192bab2d8d065f223f35fd4047d..978ba29060cac269bf8e715697479605285fae27 100644
--- a/src/main/java/org/olat/user/_spring/userContext.xml
+++ b/src/main/java/org/olat/user/_spring/userContext.xml
@@ -248,9 +248,6 @@
 	<bean id="userManager" class="org.olat.user.UserManagerImpl" >
 		<property name="userPropertiesConfig">
                 <ref bean="org.olat.user.UserPropertiesConfig" />
-        </property>
-        <property name="userNameAndPasswordSyntaxChecker">
-        	<ref bean="org.olat.user.UserNameAndPasswordSyntaxChecker"/>
         </property>
 		<property name="userDisplayNameCreator">
 			 <ref bean="${userDisplayName}"/>
@@ -260,14 +257,6 @@
 	<bean id="org.olat.core.commons.creator.UserAvatarDisplayControllerCreator"
 		class="org.olat.user.UserAvatarDisplayControllerCreatorImpl"/>
 
-	<!-- Generic regexp based email  and password checker. 
-	     If you customize this, make sure you adjusted the i18n keys                            
-	 	form.checkUsername
-		form.checkPassword
-	     of the package org.olat.user
-	-->
-	<bean id="org.olat.user.UserNameAndPasswordSyntaxChecker" class="org.olat.user.UserNameAndPasswordSyntaxCheckerWithEmail" />
-
 	<bean id="personalFolderManager" class="org.olat.user.PersonalFolderManager"/>
 	<bean class="org.olat.user.DisplayPortraitManager"/>
 	
diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties
index 3b71e76d8af551074cd3494c48f9037df40eeb39..c46a6eac9e2a833bdf465829b3fce12e5bfc9383 100644
--- a/src/main/resources/serviceconfig/olat.properties
+++ b/src/main/resources/serviceconfig/olat.properties
@@ -214,10 +214,39 @@ invitation.login=${login.invitationLogin}
 
 # Allow users to login using alternatively their email address or username
 login.using.username.or.email.enabled=true
+
+# Regex to validate username of new users. If yo change this property,
+# Make sure to change the translation of $org.olat.user\:form.checkUsername accordingly.
+username.regex=[0-9a-z\\.\\-@_]{4,32}
+
 # permit users to change their own passwords
 # (if you set this to false, nobody can can change their pws!)
 password.change.allowed=true
 
+# Password syntax checks
+password.min.length=4
+password.max.length=128
+
+# Values to restrict letters, digits and special signs
+# atLeastX:    min X letters (X = 1/2/3)
+# disabled:    The check is disabled. Letters/Digits/Specials are allowd in any quantity
+# forbidden:   Letters/Digits/Specials not allowed
+# validateSeparately: Ignore this rule and use password.min.letters.uppercase / password.min.letters.lowercase instead
+
+# By default, a password has to have at least one letter.
+password.letters=atLeast1
+password.letters.uppercase=disabled
+password.letters.lowercase=disabled
+# By default, a password has to have at least one digit or special sign.
+password.digits.special.signs=atLeast1
+password.digits=disabled
+password.special.signs=disabled
+
+# Are these values forbidden as part of the password?
+password.forbidden.username=false
+password.forbidden.firstname=false
+password.forbidden.lastname=false
+
 # Password ageing policy
 password.change.valid.hours.gui=48
 password.change.valid.hours.rest=720
diff --git a/src/test/java/org/olat/login/validation/PasswordSyntaxValidatorTest.java b/src/test/java/org/olat/login/validation/PasswordSyntaxValidatorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b1805fcdc802e3df22c8a9d6b8cebdd10c850b07
--- /dev/null
+++ b/src/test/java/org/olat/login/validation/PasswordSyntaxValidatorTest.java
@@ -0,0 +1,138 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.olat.login.validation.TestingRuleProvider.of;
+
+import java.util.List;
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.Test;
+import org.olat.core.id.Identity;
+import org.olat.login.validation.SyntaxValidator;
+import org.olat.login.validation.ValidationDescription;
+import org.olat.login.validation.ValidationResult;
+import org.olat.login.validation.ValidationRule;
+
+/**
+ * 
+ * Initial date: 13 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class PasswordSyntaxValidatorTest {
+
+	@Test
+	public void shouldValidateTrue() {
+		ValidationRule rule1 = new BooleanRule(true);
+		ValidationRule rule2 = new BooleanRule(true);
+		SyntaxValidator sut = new SyntaxValidator(of(rule1, rule2), true);
+		
+		ValidationResult result = sut.validate("123", null);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(result.isValid()).isTrue();
+		softly.assertThat(result.getInvalidDescriptions()).isEmpty();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldValidateFalse() {
+		ValidationRule rule1 = new BooleanRule(true);
+		ValidationRule rule2 = new BooleanRule(false);
+		SyntaxValidator sut = new SyntaxValidator(of(rule1, rule2), true);
+		
+		ValidationResult result = sut.validate("123", null);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(result.isValid()).isFalse();
+		softly.assertThat(result.getInvalidDescriptions()).hasSize(1);
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldValidateAll() {
+		ValidationRule rule1 = new BooleanRule(false);
+		ValidationRule rule2 = new BooleanRule(false);
+		SyntaxValidator sut = new SyntaxValidator(of(rule1, rule2), true);
+		
+		ValidationResult result = sut.validate("123", null);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(result.isValid()).isFalse();
+		softly.assertThat(result.getInvalidDescriptions()).hasSize(2);
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldBreakOnFirsInvalidRule() {
+		ValidationRule rule1 = new BooleanRule(false);
+		ValidationRule rule2 = new BooleanRule(false);
+		SyntaxValidator sut = new SyntaxValidator(of(rule1, rule2), false);
+		
+		ValidationResult result = sut.validate("123", null);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(result.isValid()).isFalse();
+		softly.assertThat(result.getInvalidDescriptions()).hasSize(1);
+		softly.assertAll();
+	}
+
+	
+	@Test
+	public void shouldGetAllDescriptions() {
+		ValidationRule rule1 = new BooleanRule(true);
+		ValidationRule rule2 = new BooleanRule(true);
+		SyntaxValidator sut = new SyntaxValidator(of(rule1, rule2), true);
+		
+		List<ValidationDescription> allDescriptions = sut.getAllDescriptions();
+		
+		assertThat(allDescriptions).hasSize(2);
+	}
+	
+	
+	private static class BooleanRule implements ValidationRule {
+		
+		private final boolean valid;
+
+		private BooleanRule(boolean valid) {
+			this.valid = valid;
+		}
+
+		@Override
+		public boolean validate(String value, Identity identity) {
+			return valid;
+		}
+
+		@Override
+		public ValidationDescription getDescription() {
+			return mock(ValidationDescription.class);
+		}
+
+		@Override
+		public boolean isIdentityRule() {
+			return false;
+		}
+
+	}
+
+}
diff --git a/src/test/java/org/olat/login/validation/PasswordValidationRuleFactoryTest.java b/src/test/java/org/olat/login/validation/PasswordValidationRuleFactoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..36f380c27e97c0bfa666273b5196d6b08d1fd844
--- /dev/null
+++ b/src/test/java/org/olat/login/validation/PasswordValidationRuleFactoryTest.java
@@ -0,0 +1,390 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.olat.core.gui.translator.Translator;
+import org.olat.core.id.Identity;
+import org.olat.core.id.User;
+import org.olat.login.validation.PasswordValidationRuleFactory;
+import org.olat.login.validation.ValidationRule;
+
+/**
+ * 
+ * Initial date: 12 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class PasswordValidationRuleFactoryTest {
+	
+	@Mock
+	private Identity iMock = mock(Identity.class);
+	
+	PasswordValidationRuleFactory sut = new TestableValidationRuleFactory();
+
+	@Test
+	public void shouldCreateVisibleCharactersRule() {
+		ValidationRule rule = sut.createVisibleCharactersRule(4, 7);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("12", iMock)).isFalse();
+		softly.assertThat(rule.validate("123", iMock)).isFalse();
+		softly.assertThat(rule.validate("1234", iMock)).isTrue();
+		softly.assertThat(rule.validate("12345", iMock)).isTrue();
+		softly.assertThat(rule.validate("123456", iMock)).isTrue();
+		softly.assertThat(rule.validate("1234567", iMock)).isTrue();
+		softly.assertThat(rule.validate("12345678", iMock)).isFalse();
+		softly.assertThat(rule.validate("abc", iMock)).isFalse();
+		softly.assertThat(rule.validate("üäö", iMock)).isFalse();
+		softly.assertThat(rule.validate("abcdefghi", iMock)).isFalse();
+		softly.assertThat(rule.validate("ab  cd", iMock)).isFalse();
+		softly.assertThat(rule.validate("abcd e", iMock)).isFalse();
+		softly.assertThat(rule.validate("ab\ncd", iMock)).isFalse();
+		softly.assertThat(rule.validate("\\u0001\\u0001\\u0001\\u0001\\u0001", iMock)).isFalse();
+		softly.assertThat(rule.validate("abcd", iMock)).isTrue();
+		softly.assertThat(rule.validate("()%&*", iMock)).isTrue();
+		softly.assertThat(rule.validate("abcdö", iMock)).isTrue();
+		softly.assertThat(rule.validate("ab__cd", iMock)).isTrue();
+		softly.assertThat(rule.validate("я́блоня", iMock)).isTrue();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isTrue();
+		softly.assertAll();
+	}
+
+	@Test
+	public void shouldCreateAtLeastLetterRule() {
+		ValidationRule rule = sut.createAtLeastLettersRule(4);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("123", iMock)).isFalse();
+		softly.assertThat(rule.validate("abc", iMock)).isFalse();
+		softly.assertThat(rule.validate("ABC", iMock)).isFalse();
+		softly.assertThat(rule.validate("üäö", iMock)).isFalse();
+		softly.assertThat(rule.validate("ಮಣೆ", iMock)).isFalse();
+		softly.assertThat(rule.validate("1234", iMock)).isFalse();
+		softly.assertThat(rule.validate("abc4", iMock)).isFalse();
+		softly.assertThat(rule.validate("abc$", iMock)).isFalse();
+		softly.assertThat(rule.validate("abc.", iMock)).isFalse();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isFalse();
+		softly.assertThat(rule.validate("\\u0001\\u0001\\u0001", iMock)).isFalse();
+		softly.assertThat(rule.validate("abcd", iMock)).isTrue();
+		softly.assertThat(rule.validate("ABCD", iMock)).isTrue();
+		softly.assertThat(rule.validate("üäöä", iMock)).isTrue();
+		softly.assertThat(rule.validate("я́блоня", iMock)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldCreateAtLeastLetterUppercaseRule() {
+		ValidationRule rule = sut.createAtLeastLettersUppercaseRule(4);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("123", iMock)).isFalse();
+		softly.assertThat(rule.validate("abc", iMock)).isFalse();
+		softly.assertThat(rule.validate("ABC", iMock)).isFalse();
+		softly.assertThat(rule.validate("üäö", iMock)).isFalse();
+		softly.assertThat(rule.validate("ಮಣೆ", iMock)).isFalse();
+		softly.assertThat(rule.validate("1234", iMock)).isFalse();
+		softly.assertThat(rule.validate("ABC4", iMock)).isFalse();
+		softly.assertThat(rule.validate("ABC$", iMock)).isFalse();
+		softly.assertThat(rule.validate("ABC.", iMock)).isFalse();
+		softly.assertThat(rule.validate("abcd", iMock)).isFalse();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isFalse();
+		softly.assertThat(rule.validate("ABCD", iMock)).isTrue();
+		softly.assertThat(rule.validate("üÜüÜüÜüÜ", iMock)).isTrue();
+		softly.assertThat(rule.validate("КГБКГБ", iMock)).isTrue();
+		softly.assertAll();
+	}
+
+	@Test
+	public void shouldCreateAtLeastLetterLowercaseRule() {
+		ValidationRule rule = sut.createAtLeastLettersLowercaseRule(4);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("123", iMock)).isFalse();
+		softly.assertThat(rule.validate("abc", iMock)).isFalse();
+		softly.assertThat(rule.validate("ABC", iMock)).isFalse();
+		softly.assertThat(rule.validate("üäö", iMock)).isFalse();
+		softly.assertThat(rule.validate("ಮಣೆ", iMock)).isFalse();
+		softly.assertThat(rule.validate("1234", iMock)).isFalse();
+		softly.assertThat(rule.validate("ABC4", iMock)).isFalse();
+		softly.assertThat(rule.validate("ABC$", iMock)).isFalse();
+		softly.assertThat(rule.validate("ABC.", iMock)).isFalse();
+		softly.assertThat(rule.validate("ABCD", iMock)).isFalse();
+		softly.assertThat(rule.validate("КГБКГБ", iMock)).isFalse();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isFalse();
+		softly.assertThat(rule.validate("abcd", iMock)).isTrue();
+		softly.assertThat(rule.validate("üÜüÜüÜüÜ", iMock)).isTrue();
+		softly.assertThat(rule.validate("я́блоня", iMock)).isTrue();
+		softly.assertAll();
+	}
+
+	@Test
+	public void shouldCreateAtLeastDigitsRule() {
+		ValidationRule rule = sut.createAtLeastDigitsRule(4);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("123", iMock)).isFalse();
+		softly.assertThat(rule.validate("abc123", iMock)).isFalse();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isFalse();
+		softly.assertThat(rule.validate("1234", iMock)).isTrue();
+		softly.assertThat(rule.validate("abc1234", iMock)).isTrue();
+		softly.assertThat(rule.validate("a1b2c3d4e", iMock)).isTrue();
+		softly.assertThat(rule.validate("1a2b3c4e5", iMock)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldCreateAtLeastSpecalSignsRule() {
+		ValidationRule rule = sut.createAtLeastSpecialSignsRule(2);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("*", iMock)).isFalse();
+		softly.assertThat(rule.validate("123", iMock)).isFalse();
+		softly.assertThat(rule.validate("abc", iMock)).isFalse();
+		softly.assertThat(rule.validate("äöü", iMock)).isFalse();
+		softly.assertThat(rule.validate("я́блоня", iMock)).isFalse();
+		softly.assertThat(rule.validate("a+.", iMock)).isTrue();
+		softly.assertThat(rule.validate("a+b£", iMock)).isTrue();
+		softly.assertThat(rule.validate("a+b£c", iMock)).isTrue();
+		softly.assertThat(rule.validate("!a+b£c", iMock)).isTrue();
+		softly.assertThat(rule.validate("!a+b£c.", iMock)).isTrue();
+		softly.assertThat(rule.validate("a$$$$$", iMock)).isTrue();
+		softly.assertThat(rule.validate("12?^", iMock)).isTrue();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isTrue();
+		// Should not be valid, but at least these passwords are invalid in LengthRule.
+		softly.assertThat(rule.validate("a   d", iMock)).isTrue();
+		softly.assertThat(rule.validate("\\u0001\\u0001\\u0001", iMock)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldCreateAtLeastDigitsOrSpecalSignsRule() {
+		ValidationRule rule = sut.createAtLeastDigitsOrSpecialSignsRule(2);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("*", iMock)).isFalse();
+		softly.assertThat(rule.validate("1", iMock)).isFalse();
+		softly.assertThat(rule.validate("abc", iMock)).isFalse();
+		softly.assertThat(rule.validate("äöü", iMock)).isFalse();
+		softly.assertThat(rule.validate("я́блоня", iMock)).isFalse();
+		softly.assertThat(rule.validate("4§", iMock)).isTrue();
+		softly.assertThat(rule.validate("a1/", iMock)).isTrue();
+		softly.assertThat(rule.validate("a+.", iMock)).isTrue();
+		softly.assertThat(rule.validate("a+b£", iMock)).isTrue();
+		softly.assertThat(rule.validate("a1b£", iMock)).isTrue();
+		softly.assertThat(rule.validate("a+b£", iMock)).isTrue();
+		softly.assertThat(rule.validate("a+b£c2", iMock)).isTrue();
+		softly.assertThat(rule.validate("!a2b£c", iMock)).isTrue();
+		softly.assertThat(rule.validate("!a3b£c.", iMock)).isTrue();
+		softly.assertThat(rule.validate("a$$$$$", iMock)).isTrue();
+		softly.assertThat(rule.validate("12?^", iMock)).isTrue();
+		// Should not be valid, but at least these passwords are invalid in LengthRule.
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isTrue();
+		softly.assertThat(rule.validate("a   d", iMock)).isTrue();
+		softly.assertThat(rule.validate("\\u0001\\u0001\\u0001", iMock)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldCreateLettersForbiddenRule() {
+		ValidationRule rule = sut.createLettersForbiddenRule();
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("1c", iMock)).isFalse();
+		softly.assertThat(rule.validate("abc", iMock)).isFalse();
+		softly.assertThat(rule.validate("äöü", iMock)).isFalse();
+		softly.assertThat(rule.validate("я́блоня", iMock)).isFalse();
+		softly.assertThat(rule.validate("*", iMock)).isTrue();
+		softly.assertThat(rule.validate("1", iMock)).isTrue();
+		softly.assertThat(rule.validate("4§", iMock)).isTrue();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isTrue();
+		softly.assertThat(rule.validate(" ", iMock)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldCreateLettersUppercaseForbiddenRule() {
+		ValidationRule rule = sut.createLettersUppercaseForbiddenRule();
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("1C", iMock)).isFalse();
+		softly.assertThat(rule.validate("aBc", iMock)).isFalse();
+		softly.assertThat(rule.validate("äÖü", iMock)).isFalse();
+		softly.assertThat(rule.validate("Гя́блоня", iMock)).isFalse();
+		softly.assertThat(rule.validate("*", iMock)).isTrue();
+		softly.assertThat(rule.validate("1", iMock)).isTrue();
+		softly.assertThat(rule.validate("1c", iMock)).isTrue();
+		softly.assertThat(rule.validate("4§", iMock)).isTrue();
+		softly.assertThat(rule.validate("äü", iMock)).isTrue();
+		softly.assertThat(rule.validate("abc", iMock)).isTrue();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isTrue();
+		softly.assertThat(rule.validate(" ", iMock)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldCreateLettersLowercaseForbiddenRule() {
+		ValidationRule rule = sut.createLettersLowercaseForbiddenRule();
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("1c", iMock)).isFalse();
+		softly.assertThat(rule.validate("aBc", iMock)).isFalse();
+		softly.assertThat(rule.validate("äÖü", iMock)).isFalse();
+		softly.assertThat(rule.validate("Гя́блоня", iMock)).isFalse();
+		softly.assertThat(rule.validate("*", iMock)).isTrue();
+		softly.assertThat(rule.validate("1", iMock)).isTrue();
+		softly.assertThat(rule.validate("1C", iMock)).isTrue();
+		softly.assertThat(rule.validate("4§", iMock)).isTrue();
+		softly.assertThat(rule.validate("ÖÜ", iMock)).isTrue();
+		softly.assertThat(rule.validate("ABC", iMock)).isTrue();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isTrue();
+		softly.assertThat(rule.validate(" ", iMock)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldCreateDigitsForbiddenRule() {
+		ValidationRule rule = sut.createDigitsForbiddenRule();
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("1", iMock)).isFalse();
+		softly.assertThat(rule.validate("1c", iMock)).isFalse();
+		softly.assertThat(rule.validate("4§", iMock)).isFalse();
+		softly.assertThat(rule.validate("123", iMock)).isFalse();
+		softly.assertThat(rule.validate("abd", iMock)).isTrue();
+		softly.assertThat(rule.validate("äöü", iMock)).isTrue();
+		softly.assertThat(rule.validate("я́блоня", iMock)).isTrue();
+		softly.assertThat(rule.validate("*", iMock)).isTrue();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isTrue();
+		softly.assertThat(rule.validate(" ", iMock)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldCreateSpecialSignsForbiddenRule() {
+		ValidationRule rule = sut.createSpecialSignsForbiddenRule();
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("*", iMock)).isFalse();
+		softly.assertThat(rule.validate("4%", iMock)).isFalse();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isFalse();
+		softly.assertThat(rule.validate("a v", iMock)).isFalse();
+		softly.assertThat(rule.validate("\\u0001cd", iMock)).isFalse();
+		softly.assertThat(rule.validate("1c", iMock)).isTrue();
+		softly.assertThat(rule.validate("aBc", iMock)).isTrue();
+		softly.assertThat(rule.validate("äÖü", iMock)).isTrue();
+		softly.assertThat(rule.validate("я́блоня", iMock)).isTrue();
+		softly.assertThat(rule.validate("1", iMock)).isTrue();
+		softly.assertThat(rule.validate("1C", iMock)).isTrue();
+		softly.assertThat(rule.validate("ÖÜ", iMock)).isTrue();
+		softly.assertThat(rule.validate("ABC", iMock)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldCreateDigitsAndSpecialSignsForbiddenRule() {
+		ValidationRule rule = sut.createDigitsAndSpecialSignsForbiddenRule();
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("*", iMock)).isFalse();
+		softly.assertThat(rule.validate("4%", iMock)).isFalse();
+		softly.assertThat(rule.validate("😀😀😀😀", iMock)).isFalse();
+		softly.assertThat(rule.validate("a v", iMock)).isFalse();
+		softly.assertThat(rule.validate("\\u0001cd", iMock)).isFalse();
+		softly.assertThat(rule.validate("1", iMock)).isFalse();
+		softly.assertThat(rule.validate("1C", iMock)).isFalse();
+		softly.assertThat(rule.validate("1c", iMock)).isFalse();
+		softly.assertThat(rule.validate("aBc", iMock)).isTrue();
+		softly.assertThat(rule.validate("äÖü", iMock)).isTrue();
+		softly.assertThat(rule.validate("я́блоня", iMock)).isTrue();
+		softly.assertThat(rule.validate("ÖÜ", iMock)).isTrue();
+		softly.assertThat(rule.validate("ABC", iMock)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldUsernameForbiddenRule() {
+		ValidationRule rule = sut.createUsernameForbiddenRule();
+		
+		Identity identity = mock(Identity.class);
+		when(identity.getName()).thenReturn("myname");
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("myname", identity)).isFalse();
+		softly.assertThat(rule.validate("MYNAME", identity)).isFalse();
+		softly.assertThat(rule.validate("$$$MYNAME$$$", identity)).isFalse();
+		softly.assertThat(rule.validate("myname01", identity)).isFalse();
+		softly.assertThat(rule.validate("superman", identity)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldUserFirstnameForbiddenRule() {
+		ValidationRule rule = sut.createUserFirstnameForbiddenRule();
+		
+		User user = mock(User.class);
+		when(user.getFirstName()).thenReturn("myname");
+		Identity identity = mock(Identity.class);
+		when(identity.getUser()).thenReturn(user);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("myname", identity)).isFalse();
+		softly.assertThat(rule.validate("MYNAME", identity)).isFalse();
+		softly.assertThat(rule.validate("$$$MYNAME$$$", identity)).isFalse();
+		softly.assertThat(rule.validate("myname01", identity)).isFalse();
+		softly.assertThat(rule.validate("superman", identity)).isTrue();
+		softly.assertAll();
+	}
+	
+	@Test
+	public void shouldUserLastnameForbiddenRule() {
+		ValidationRule rule = sut.createUserLastnameForbiddenRule();
+		
+		User user = mock(User.class);
+		when(user.getLastName()).thenReturn("myname");
+		Identity identity = mock(Identity.class);
+		when(identity.getUser()).thenReturn(user);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(rule.validate("myname", identity)).isFalse();
+		softly.assertThat(rule.validate("MYNAME", identity)).isFalse();
+		softly.assertThat(rule.validate("$$$MYNAME$$$", identity)).isFalse();
+		softly.assertThat(rule.validate("myname01", identity)).isFalse();
+		softly.assertThat(rule.validate("superman", identity)).isTrue();
+		softly.assertAll();
+	}
+
+	
+	
+	private static class TestableValidationRuleFactory extends PasswordValidationRuleFactory {
+
+		@Override
+		protected Translator createTranslator() {
+			return mock(Translator.class);
+		}
+		
+	}
+
+}
diff --git a/src/test/java/org/olat/login/validation/TestingRuleProvider.java b/src/test/java/org/olat/login/validation/TestingRuleProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f6fffb31af6131762d17540062fbd4637069002
--- /dev/null
+++ b/src/test/java/org/olat/login/validation/TestingRuleProvider.java
@@ -0,0 +1,61 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.login.validation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.login.validation.ValidationRule;
+import org.olat.login.validation.ValidationRulesProvider;
+
+
+/**
+ * 
+ * Initial date: 13 May 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+class TestingRuleProvider implements ValidationRulesProvider {
+
+	private List<ValidationRule> rules;
+	
+	static TestingRuleProvider of(ValidationRule rule) {
+		List<ValidationRule> rules = new ArrayList<>(1);
+		rules.add(rule);
+		return new TestingRuleProvider(rules);
+	}
+	
+	static TestingRuleProvider of(ValidationRule rule1, ValidationRule rule2) {
+		List<ValidationRule> rules = new ArrayList<>(2);
+		rules.add(rule1);
+		rules.add(rule2);
+		return new TestingRuleProvider(rules);
+	}
+	
+	private TestingRuleProvider(List<ValidationRule> rules) {
+		this.rules = rules;
+	}
+
+	@Override
+	public List<ValidationRule> getRules() {
+		return rules;
+	}
+	
+}
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index 1c0aa676ef1f2e8808cfd8fdb74529dc6060669f..878bc08527b90e06bd5f9e110befe32be6573a4e 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -149,7 +149,6 @@ import org.junit.runners.Suite;
 	org.olat.basesecurity.BaseSecurityManagerTest.class,
 	org.olat.user.UserDAOTest.class,
 	org.olat.user.UserManagerTest.class,
-	org.olat.user.UserNameAndPasswordSyntaxCheckerWithRegexpTest.class,
 	org.olat.user.manager.UserDataExportDAOTest.class,
 	org.olat.user.manager.UserDataExportServiceTest.class,
 	org.olat.repository.manager.AutomaticLifecycleServiceTest.class,
@@ -448,6 +447,8 @@ import org.junit.runners.Suite;
 	org.olat.core.gui.components.form.flexible.impl.elements.richText.TextModeTest.class,
 	org.olat.core.gui.components.form.flexible.impl.elements.SelectboxSelectionImplTest.class,
 	org.olat.core.gui.components.form.flexible.impl.elements.TextElementRendererTest.class,
+	org.olat.login.validation.PasswordSyntaxValidatorTest.class,
+	org.olat.login.validation.PasswordValidationRuleFactoryTest.class,
 	org.olat.modules.card2brain.manager.Card2BrainManagerImplTest.class,
 	org.olat.modules.edubase.manager.EdubaseManagerImplTest.class,
 	org.olat.modules.edusharing.manager.EdusharingHtmlServiceImplTest.class,
diff --git a/src/test/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithRegexpTest.java b/src/test/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithRegexpTest.java
deleted file mode 100644
index 6f821f2b2b09d7256bde3961ff8aa06c9d6b2da8..0000000000000000000000000000000000000000
--- a/src/test/java/org/olat/user/UserNameAndPasswordSyntaxCheckerWithRegexpTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.user;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-/**
- * 
- * Initial date: 23.08.2013<br>
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- *
- */
-public class UserNameAndPasswordSyntaxCheckerWithRegexpTest {
-	
-	@Test
-	public void defaultPasswordCheck() {
-		UserNameAndPasswordSyntaxCheckerWithRegexp checker = new UserNameAndPasswordSyntaxCheckerWithRegexp();
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("Kan"));
-		Assert.assertTrue(checker.syntaxCheckOlatPassword("Kanu#01"));
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("Kan\u00FC#01"));
-	}
-	
-	/**
-	 * Min. 7 characters, one uppercase, one lowercase, one number
-	 */
-	@Test
-	public void customPasswordCheck_upperLowerCase_number() {
-		UserNameAndPasswordSyntaxCheckerWithRegexp checker = new UserNameAndPasswordSyntaxCheckerWithRegexp();
-		checker.setPasswordRegExp("(?=^.{7,}$)((?=.*\\d)|(?=.*\\W+))(?![.\\n])(?=.*[A-Z])(?=.*[a-z]).*$");
-		
-		Assert.assertTrue(checker.syntaxCheckOlatPassword("Kanu#01"));
-		Assert.assertTrue(checker.syntaxCheckOlatPassword("Kanuunc1"));
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanu#1"));//less than 7 characters
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanuunch"));//no number	Kan\u00FC
-		Assert.assertTrue(checker.syntaxCheckOlatPassword("Kan\u00FCunc1"));// Umlaut allowed
-	}
-	
-	/**
-	 * Min. 8 characters, one uppercase, one lowercase, one number, one special character
-	 */
-	@Test
-	public void customPasswordCheck_upperLowerCase_number_special() {
-		UserNameAndPasswordSyntaxCheckerWithRegexp checker = new UserNameAndPasswordSyntaxCheckerWithRegexp();
-		checker.setPasswordRegExp("(?=^.{8,}$)((?=.*\\d)|(?=.*\\W+))(?![.\\n])(?=.*[A-Z])(?=.*[a-z])(?=.*[$@$!%*#?&]).*$");
-
-		Assert.assertTrue(checker.syntaxCheckOlatPassword("Kanu#010"));
-		Assert.assertTrue(checker.syntaxCheckOlatPassword("?Ryomou#010"));
-		Assert.assertTrue(checker.syntaxCheckOlatPassword("?Ryo ou#010"));
-		
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanuunc1"));
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanu#10"));//less than 8 characters
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanuunch"));//no number
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("kanu8#10"));
-	}
-	
-	/**
-	 * Min. 12 characters, at least one uppercase, one lowercase, one number and only
-	 * alphanumeric characters allowed (no space, no underscore, no Umlaut)
-	 */
-	@Test
-	public void customPasswordCheck_upperLowerCase_number_noUmlaut() {
-		UserNameAndPasswordSyntaxCheckerWithRegexp checker = new UserNameAndPasswordSyntaxCheckerWithRegexp();
-		checker.setPasswordRegExp("(?=^.{12,}$)(?=^[a-zA-Z0-9]+$)(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z]).*$");
-
-		Assert.assertTrue(checker.syntaxCheckOlatPassword("Kanu1asdfghj"));
-		Assert.assertTrue(checker.syntaxCheckOlatPassword("KASD123DFGHJj"));
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanuhasdfghj"));
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("kanu1asdfghj"));
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("kanugasdfghj"));
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanu1as fghj"));
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("Kanu1as_fghj"));
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("kanugasdfgh"));
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("JAHDFKL1DFSGJHG"));
-		Assert.assertFalse(checker.syntaxCheckOlatPassword("Kan\u00E41asdfghj"));
-	}
-
-	
-}