diff --git a/api/src/main/resources/messages.properties b/api/src/main/resources/messages.properties index 8f21ed23..496086a9 100644 --- a/api/src/main/resources/messages.properties +++ b/api/src/main/resources/messages.properties @@ -16,6 +16,11 @@ adminui.noname=No Name adminui.field.too.long=The value you entered is too long adminui.field.exceeded.maxChars=A maximum of {0} character(s) is allowed adminui.field.require.minChars=At least {0} character(s) are required +adminui.field.require.pattern.begin=This password must have: +adminui.field.require.pattern.reqUpperAndLowerCase=both upper and lowercase characters +adminui.field.require.pattern.reqDigit=at least one digit +adminui.field.require.pattern.reqNonDigit=at least one non digit +adminui.field.require.pattern.reqRegex=match this Regex pattern: {0} adminui.retire=Retire {0}? adminui.purge=Delete {0} Forever? adminui.requiredField.label=required diff --git a/omod/src/main/java/org/openmrs/module/adminui/page/controller/PasswordValidation.java b/omod/src/main/java/org/openmrs/module/adminui/page/controller/PasswordValidation.java new file mode 100644 index 00000000..cecd80b1 --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/adminui/page/controller/PasswordValidation.java @@ -0,0 +1,63 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.adminui.page.controller; + +import org.apache.commons.lang.StringUtils; +import org.openmrs.api.AdministrationService; +import org.openmrs.api.context.Context; +import org.openmrs.messagesource.MessageSourceService; +import org.openmrs.ui.framework.page.PageModel; +import org.openmrs.util.OpenmrsConstants; + +public final class PasswordValidation { + private PasswordValidation() { + + } + + public static void addPasswordValidationAttributes(PageModel model, AdministrationService adminService, MessageSourceService mss) { + String passwordMinLength = adminService.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_MINIMUM_LENGTH, "8"); + boolean passwordReqUpperAndLowerCase = "true".equals(adminService.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_UPPER_AND_LOWER_CASE, "true")); + boolean passwordReqDigit = "true".equals(adminService.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_DIGIT, "true")); + boolean passwordReqNonDigit = "true".equals(adminService.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_NON_DIGIT, "true")); + String passwordReqRegex = adminService.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_CUSTOM_REGEX, ""); + + String pattern = ""; + String patternErrorMessage = ""; + + if (passwordReqUpperAndLowerCase || passwordReqDigit || passwordReqNonDigit || StringUtils.isNotEmpty(passwordReqRegex)) { + pattern += "/^"; + patternErrorMessage += mss.getMessage("adminui.field.require.pattern.begin"); + if (passwordReqUpperAndLowerCase) { + pattern += "(?=.*?[A-Z])(?=.*?[a-z])"; + patternErrorMessage += ' ' + mss.getMessage("adminui.field.require.pattern.reqUpperAndLowerCase") + ','; + } + if (passwordReqDigit) { + pattern += "(?=.*\\d)"; + patternErrorMessage += ' ' + mss.getMessage("adminui.field.require.pattern.reqDigit") + ','; + } + if (passwordReqNonDigit) { + pattern += "(?=.*[^\\d])"; + patternErrorMessage += ' ' + mss.getMessage("adminui.field.require.pattern.reqNonDigit") + ','; + } + if (StringUtils.isNotEmpty(passwordReqRegex)) { + pattern += "(?="; + pattern += passwordReqRegex; + pattern += ')'; + patternErrorMessage += ' ' + mss.getMessage("adminui.field.require.pattern.reqRegex", new Object[]{passwordReqRegex}, Context.getLocale()) + ','; + } + pattern += "[\\w|\\W]*$/"; + patternErrorMessage = patternErrorMessage.substring(0, patternErrorMessage.length() - 1); + } + + model.addAttribute("passwordMinLength", passwordMinLength); + model.addAttribute("pattern", pattern); + model.addAttribute("patternErrorMessage", patternErrorMessage); + } +} diff --git a/omod/src/main/java/org/openmrs/module/adminui/page/controller/myaccount/ChangePasswordPageController.java b/omod/src/main/java/org/openmrs/module/adminui/page/controller/myaccount/ChangePasswordPageController.java index ae6a2b5d..5d1ca069 100644 --- a/omod/src/main/java/org/openmrs/module/adminui/page/controller/myaccount/ChangePasswordPageController.java +++ b/omod/src/main/java/org/openmrs/module/adminui/page/controller/myaccount/ChangePasswordPageController.java @@ -23,6 +23,7 @@ import org.openmrs.api.context.Context; import org.openmrs.api.db.DAOException; import org.openmrs.messagesource.MessageSourceService; +import org.openmrs.module.adminui.page.controller.PasswordValidation; import org.openmrs.module.uicommons.UiCommonsConstants; import org.openmrs.module.uicommons.util.InfoErrorMessageUtil; import org.openmrs.ui.framework.annotation.SpringBean; @@ -48,13 +49,14 @@ public String overridePostChangePassword() { return "forward:/adminui/myaccount/changePassword.page"; } - public void get(PageModel model, @SpringBean("adminService") AdministrationService adminService) { - setModelAttributes(model, adminService); + public void get(PageModel model, + @SpringBean("adminService") AdministrationService adminService, + @SpringBean("messageSourceService") MessageSourceService mss) { + setModelAttributes(model, adminService, mss); } - public void setModelAttributes(PageModel model, AdministrationService adminService) { - model.addAttribute("passwordMinLength", - adminService.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_MINIMUM_LENGTH, "8")); + public void setModelAttributes(PageModel model, AdministrationService adminService, MessageSourceService mss) { + PasswordValidation.addPasswordValidationAttributes(model, adminService, mss); } public String post(PageModel model, @SpringBean("userService") UserService userService, @@ -77,7 +79,7 @@ public String post(PageModel model, @SpringBean("userService") UserService userS if (errorMessage == null) { try { OpenmrsUtil.validatePassword(user.getUsername(), newPassword, user.getSystemId()); - + String nextPage = "redirect:/index.htm"; try { userService.changePassword(oldPassword, newPassword); @@ -132,7 +134,7 @@ public String post(PageModel model, @SpringBean("userService") UserService userS request.getSession().setAttribute(UiCommonsConstants.SESSION_ATTRIBUTE_ERROR_MESSAGE, errorMessage); - setModelAttributes(model, adminService); + setModelAttributes(model, adminService, mss); return "myaccount/changePassword"; } diff --git a/omod/src/main/java/org/openmrs/module/adminui/page/controller/systemadmin/accounts/AccountPageController.java b/omod/src/main/java/org/openmrs/module/adminui/page/controller/systemadmin/accounts/AccountPageController.java index 0784f99b..4c5abcec 100644 --- a/omod/src/main/java/org/openmrs/module/adminui/page/controller/systemadmin/accounts/AccountPageController.java +++ b/omod/src/main/java/org/openmrs/module/adminui/page/controller/systemadmin/accounts/AccountPageController.java @@ -35,6 +35,7 @@ import org.openmrs.module.adminui.account.Account; import org.openmrs.module.adminui.account.AccountService; import org.openmrs.module.adminui.account.AdminUiAccountValidator; +import org.openmrs.module.adminui.page.controller.PasswordValidation; import org.openmrs.module.appframework.domain.Extension; import org.openmrs.module.appframework.service.AppFrameworkService; import org.openmrs.module.providermanagement.Provider; @@ -88,12 +89,13 @@ public Account getAccount(@RequestParam(value = "personId", required = false) Pe public void get(PageModel model, @MethodParam("getAccount") Account account, @SpringBean("adminAccountService") AccountService accountService, @SpringBean("adminService") AdministrationService administrationService, + @SpringBean("messageSourceService") MessageSourceService mss, @SpringBean("providerManagementService") ProviderManagementService providerManagementService, UiUtils uu, @SpringBean("appFrameworkService") AppFrameworkService appFrameworkService) throws IOException { - setModelAttributes(model, account, null, accountService, administrationService, providerManagementService, uu, appFrameworkService); + setModelAttributes(model, account, null, accountService, administrationService, mss, providerManagementService, uu, appFrameworkService); if (account.getPerson().getPersonId() == null) { setJsonFormData(model, account, null); } @@ -115,6 +117,7 @@ public String post(PageModel model, @MethodParam("getAccount") @BindParams Accou @SpringBean("messageSourceService") MessageSourceService messageSourceService, @SpringBean("adminAccountService") AccountService accountService, @SpringBean("adminService") AdministrationService administrationService, + @SpringBean("messageSourceService") MessageSourceService mss, @SpringBean("adminUiAccountValidator") AdminUiAccountValidator accountValidator, @SpringBean("providerManagementService") ProviderManagementService providerManagementService, @SpringBean("appFrameworkService") AppFrameworkService appFrameworkService, @@ -211,7 +214,7 @@ public String post(PageModel model, @MethodParam("getAccount") @BindParams Accou } } - setModelAttributes(model, account, otherAccountData, accountService, administrationService, + setModelAttributes(model, account, otherAccountData, accountService, administrationService, mss, providerManagementService, uu, appFrameworkService); sendErrorMessage(errors, model, messageSourceService, request); @@ -226,8 +229,8 @@ public String post(PageModel model, @MethodParam("getAccount") @BindParams Accou public void setModelAttributes(PageModel model, Account account, OtherAccountData otherAccountData, AccountService accountService, AdministrationService administrationService, - ProviderManagementService providerManagementService, UiUtils uu, - AppFrameworkService appFrameworkService) throws IOException { + MessageSourceService mss, ProviderManagementService providerManagementService, + UiUtils uu, AppFrameworkService appFrameworkService) throws IOException { model.addAttribute("account", account); Boolean forcePasswordChange = null; @@ -284,8 +287,7 @@ public void setModelAttributes(PageModel model, Account account, OtherAccountDat propertyMaxLengthMap.put("username", administrationService.getMaximumPropertyLength(User.class, "username")); propertyMaxLengthMap.put("password", administrationService.getMaximumPropertyLength(User.class, "password")); model.addAttribute("propertyMaxLengthMap", propertyMaxLengthMap); - model.addAttribute("passwordMinLength", - administrationService.getGlobalProperty(OpenmrsConstants.GP_PASSWORD_MINIMUM_LENGTH, "8")); + PasswordValidation.addPasswordValidationAttributes(model, administrationService, mss); ObjectMapper mapper = new ObjectMapper(); SimpleObject so = new SimpleObject(); diff --git a/omod/src/main/webapp/fragments/systemadmin/accounts/userFormFields.gsp b/omod/src/main/webapp/fragments/systemadmin/accounts/userFormFields.gsp index 91b6aff9..50dccf77 100644 --- a/omod/src/main/webapp/fragments/systemadmin/accounts/userFormFields.gsp +++ b/omod/src/main/webapp/fragments/systemadmin/accounts/userFormFields.gsp @@ -42,6 +42,10 @@ passwordAttributes[requiredAttribute] = requiredAttributeValue; } + if (pattern) { + passwordAttributes.put("ng-pattern", pattern); + } + def otherPasswordAttributes= ["ng-model": "uuidUserMap['"+userUuid+"'].password"] otherPasswordAttributes.putAll(passwordAttributes) %> @@ -104,8 +108,13 @@ ${ui.message("adminui.field.required")} - ${ui.message("adminui.field.require.minChars", passwordMinLength)} + ${ui.message("adminui.field.require.minChars", passwordMinLength)}
+
+ <% if (pattern) { %> + + ${patternErrorMessage} + <% } %> @@ -159,4 +168,4 @@ <% } %> <% } %> - \ No newline at end of file + diff --git a/omod/src/main/webapp/pages/myaccount/changePassword.gsp b/omod/src/main/webapp/pages/myaccount/changePassword.gsp index 609541ae..a91a5075 100644 --- a/omod/src/main/webapp/pages/myaccount/changePassword.gsp +++ b/omod/src/main/webapp/pages/myaccount/changePassword.gsp @@ -7,6 +7,11 @@ ui.includeCss("adminui", "adminui.css") + def passwordAttributes = ["ng-model": "newPassword", required:"", "ng-minlength": passwordMinLength] + + if (pattern) { + passwordAttributes.put("ng-pattern", pattern) + } %>