Index: user-tool/tool/src/bundle/admin.properties =================================================================== --- user-tool/tool/src/bundle/admin.properties (revision 308072) +++ user-tool/tool/src/bundle/admin.properties (working copy) @@ -55,6 +55,7 @@ useedi.revuseinf = Review User Information useedi.sav = Update Details useedi.sav2 = Save Details +useedi.edit = Edit Account uselis.users = Users uselis.lisof = List of Users. First column: user ID. Second: the name. Third: email address. Fourth: user type. @@ -110,3 +111,12 @@ disable.user=Disable User disable=Disable disabled=Disabled + +# plukasew, bjones86 - SAK-23568 +pw.fail = Password strength: too weak +pw.weak = Password strength: weak +pw.moderate = Password strength: moderate +pw.strong = Password strength: strong +pw.strengthInfo = Strong passwords are long and/or use a mix of character types (ie. letters, numbers, symbols, etc.). They do not contain all or part of the user id. +pw.match = Passwords match +pw.noMatch = Passwords do not match \ No newline at end of file Index: user-tool/tool/src/java/org/sakaiproject/user/tool/PasswordPolicyHelper.java =================================================================== --- user-tool/tool/src/java/org/sakaiproject/user/tool/PasswordPolicyHelper.java (revision 0) +++ user-tool/tool/src/java/org/sakaiproject/user/tool/PasswordPolicyHelper.java (working copy) @@ -0,0 +1,157 @@ +/****************************************************************************** + * $URL$ + * $Id$ + ****************************************************************************** + * + * Copyright (c) 2003-2014 The Apereo Foundation + * + * Licensed under the Educational Community License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/ecl2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ + + +package org.sakaiproject.user.tool; + +import lombok.Getter; +import lombok.Setter; +import org.sakaiproject.cheftool.Context; +import org.sakaiproject.component.cover.ComponentManager; +import org.sakaiproject.entity.api.ResourceProperties; +import org.sakaiproject.time.api.Time; +import org.sakaiproject.user.api.User; +import org.sakaiproject.user.api.UserDirectoryService; +import org.sakaiproject.user.api.UserDirectoryService.PasswordRating; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.Date; +import java.util.Stack; + +/** + * Utility class for enforcing password policy + * @author plukasew, bjones86 - SAK-23568 + */ +@SuppressWarnings("deprecation") +public class PasswordPolicyHelper { + /** User directory API */ + private static UserDirectoryService uds = (UserDirectoryService) ComponentManager.get(UserDirectoryService.class); + + /** velocity param name for password policy enabled/disabled */ + private static final String JS_ENABLED_KEY = "isPasswordPolicyEnabled"; + + /** velocity param value for password policy enabled/disabled */ + private static final boolean policyEnabled = (uds.getPasswordPolicy() != null); + + /** + * Default zero-arg constructor + */ + public PasswordPolicyHelper() {} + + /** + * Validate the given password for the given user + * @param password + * the password to be validated + * @param user + * the user the password belongs to + * @return true/false (valid/invalid) + */ + public PasswordRating validatePassword(String password, User user) { + if (policyEnabled) { + return uds.validatePassword(password, user); + } + return PasswordRating.PASSED_DEFAULT; + } + + /** + * Add necessary parameters into the context for password policy enforcement + * @param context + */ + public void addJavaScriptParamsToContext(Context context) { + context.put(JS_ENABLED_KEY, policyEnabled); + } + + /** + * This class is needed to allow input and output since the User/UserEdit classes are too hard to work with + */ + @SuppressWarnings("unused") + public static class TempUser implements User { + @Getter @Setter private String eid; + @Getter @Setter private String email; + @Getter @Setter private String firstName; + @Getter @Setter private String lastName; + @Getter @Setter private String displayName; + @Getter @Setter private String password; + @Getter @Setter private String type; + + /** + * Default zero-arg constructor. + * DO NOT USE! + */ + public TempUser() {} + + /** + * Constructor + * + * @param eid + * the user's external ID + * @param email + * the user's email address + * @param firstName + * the user's first name + * @param lastName + * the user's last name + * @param displayName + * the user's display name + * @param password + * the user's password + * @param type + * the user's type + */ + public TempUser(String eid, String email, String firstName, String lastName, String displayName, String password, String type) { + this.eid = eid; + this.password = password; + this.email = email; + this.firstName = firstName; + this.lastName = lastName; + this.displayName = displayName; + this.type = type; + } + + /*********************************************************************************************** + ********************************* UNIMPLEMENTED METHODS *************************************** + ***********************************************************************************************/ + @Override public ResourceProperties getProperties() { return null; } + @Override public Element toXml(Document arg0, Stack arg1) { return null; } + @Override public boolean checkPassword(String arg0) { return false; } + @Override public String getId() { return null; } + @Override public String getDisplayId() { return null; } + @Override public String getDisplayName() { return null; } + @Override public String getEid() { return null; } + @Override public String getEmail() { return null; } + @Override public String getFirstName() { return null; } + @Override public String getLastName() { return null; } + @Override public String getReference() { return null; } + @Override public String getReference(String arg0) { return null; } + @Override public String getUrl() { return null; } + @Override public String getUrl(String arg0) { return null; } + @Override public String getSortName() { return null; } + @Override public String getType() { return null; } + @Override public User getModifiedBy() { return null; } + @Override public User getCreatedBy() { return null; } + @Override public Date getCreatedDate() { return null; } + @Override public Date getModifiedDate() { return null; } + @Override public Time getCreatedTime() { return null; } + @Override public Time getModifiedTime() { return null; } + @Override public int compareTo(Object o) { return 0; } + } +} Property changes on: user-tool/tool/src/java/org/sakaiproject/user/tool/PasswordPolicyHelper.java ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +Date Revision Author HeadURL Id \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: user-tool/tool/src/java/org/sakaiproject/user/tool/UsersAction.java =================================================================== --- user-tool/tool/src/java/org/sakaiproject/user/tool/UsersAction.java (revision 308072) +++ user-tool/tool/src/java/org/sakaiproject/user/tool/UsersAction.java (working copy) @@ -73,8 +73,10 @@ import org.sakaiproject.user.api.UserLockedException; import org.sakaiproject.user.api.UserNotDefinedException; import org.sakaiproject.user.api.UserPermissionException; +import org.sakaiproject.user.api.UserDirectoryService.PasswordRating; import org.sakaiproject.user.cover.AuthenticationManager; import org.sakaiproject.user.cover.UserDirectoryService; +import org.sakaiproject.user.tool.PasswordPolicyHelper.TempUser; import org.sakaiproject.util.BaseResourcePropertiesEdit; import org.sakaiproject.util.ExternalTrustedEvidence; import org.sakaiproject.util.RequestFilter; @@ -103,6 +105,11 @@ private static final String IMPORT_PASSWORD="password"; private static final String IMPORT_TYPE="type"; + // SAK-23568 + private static final PasswordPolicyHelper pwHelper = new PasswordPolicyHelper(); + private static final String MSG_KEY_PASSWORD_WEAK = "pw.weak"; + private static final String MSG_KEY_PW_STRENGTH_INFO = "pw.strengthInfo"; + /** * {@inheritDoc} */ @@ -239,7 +246,10 @@ //put successMessage into context and remove from state context.put("successMessage", state.getAttribute("successMessage")); state.removeAttribute("successMessage"); - + + // SAK-23568 + pwHelper.addJavaScriptParamsToContext(context); + // check mode and dispatch String mode = (String) state.getAttribute("mode"); @@ -1013,6 +1023,25 @@ } // doCancel_remove /** + * Check to see if password meets requirements set in password policy. + * If current user is admin, ignores password policy. + * + * @author plukasew, bjones86 - SAK-23568 + * + * @param pw the password + * @param user the user + * @param state the session state + * @return true if password is valid or if current user is admin + */ + private boolean validatePassword(String pw, User user, SessionState state) { + if (pw != null && !SecurityService.isSuperUser() && pwHelper.validatePassword(pw, user) == PasswordRating.FAILED) { + addAlert(state, rb.getString(MSG_KEY_PASSWORD_WEAK) + " " + rb.getString(MSG_KEY_PW_STRENGTH_INFO)); + return false; + } + return true; + } + + /** * Read the user form and update the user in state. * * @return true if the form is accepted, false if there's a validation error (an alertMessage will be set) @@ -1179,6 +1208,12 @@ return false; } + // SAK-23568 - make sure password meets policy requirements + TempUser tempUser = new TempUser(eid, null, null, null, eid, pw, null); + if (!validatePassword(pw, tempUser, state)) { + return false; + } + try { // add the user in one step so that all you need is add not update permission @@ -1304,7 +1339,12 @@ addAlert(state, rb.getString("usecre.pass")); return false; } - + + // SAK-23568 - make sure password meets policy requirements + if (!validatePassword(pw, user, state)) { + return false; + } + if (pw != null) user.setPassword(pw); } } Index: user-tool/tool/src/webapp/css/sakai-user-tool.css =================================================================== --- user-tool/tool/src/webapp/css/sakai-user-tool.css (revision 0) +++ user-tool/tool/src/webapp/css/sakai-user-tool.css (working copy) @@ -0,0 +1,190 @@ +#user-create_edit label, #useredit label +{ + margin-top: 0; + font-weight: bold; + color: rgb(85, 85, 85); +} + +#user-create_edit .shorttext label +{ + display: inline-block; + float: none; + text-align: right; + width: 12em; +} + +#useredit .shorttext label +{ + display: inline-block; + float: none; + text-align: right; + width: 12em; +} + +#user-create_edit .reqStar, #useredit .reqStar +{ + float: none; +} + +#user-create_edit input[type="text"], #user-create_edit input[type="password"] +, #useredit input[type="text"], #useredit input[type="password"] +{ + width: 185px; +} + +#user-create_edit #strengthInfo, #useredit #strengthInfo +{ + display: block; + position: absolute; + left: 32.5em; + width: 25%; + margin-top: -5em; + padding: 1em; + border: 1px solid #ccc; + border-radius: 5px; + box-shadow: 1px 2px 3px rgba(0, 0, 0, 0.2); + background-color: #fff; + color: #000; +} + +#user-create_edit #strengthInfo:before, #useredit #strengthInfo:before +{ + content: ""; + position: absolute; + width: 0; + height: 0; + top: 3px; + left: -15px; + border-top: 15px solid transparent; + border-right: 15px solid #ccc; + border-bottom: 15px solid transparent; +} + +#user-create_edit #matchMsg, #user-create_edit #strongMsg, #user-create_edit #noMatchMsg, #user-create_edit #weakMsg, +#useredit #matchMsg, #useredit #strongMsg, #useredit #noMatchMsg, #useredit #weakMsg, #user-create_edit #emailWarningMsg, +#useredit #emailWarningMsg, #useredit #curPassReqMsg, #user-create_edit #failMsg, #user-create_edit #moderateMsg, +#useredit #failMsg, #useredit #moderateMsg +{ + display: block; + margin: 0.5em 0 0 13.5em; + padding-left: 1.5em; + vertical-align: top; + line-height: 1.4em; +} + +#user-create_edit #noMatchMsg, #user-create_edit #failMsg, #useredit #noMatchMsg, #useredit #failMsg, +#user-create_edit #emailWarningMsg, #useredit #emailWarningMsg, #useredit #curPassReqMsg +{ + background: transparent url("/library/image/silk/cancel.png") no-repeat left center; + color: #000; +} + +#user-create_edit #matchMsg, #user-create_edit #strongMsg, #useredit #matchMsg, #useredit #strongMsg, +#user-create_edit #moderateMsg, #useredit #moderateMsg, #user-create_edit #weakMsg, #useredit #weakMsg +{ + background: transparent url("/library/image/silk/accept.png") no-repeat left center; + color: #000; +} + +#user-create_edit #strengthBar, #useredit #strengthBar +{ + background-color: #ccc; + width: 188px; + height: 5px; + margin: 5px 0px 0px 13.5em; + text-align: left; +} + +#user-create_edit #strengthBarMeter, #useredit #strengthBarMeter +{ + display: inline-block; + width: 0%; + height: 100%; + background-color: #900; +} + +#user-create_edit .act input[type="submit"], #useredit .act input[type="submit"], +#userViewForm .act input[type="submit"] +{ + display: inline-block; + margin: 0 1em; +} + +#userViewForm label +{ + font-weight: bold; + color: rgb(85, 85, 85); + display: inline-block; + float: none; + text-align: right; + margin-right: 1em; + width: 9em; +} + +#userViewForm .act, #user-create_edit .act, #useredit .act +{ + text-align: right; +} + +.act .active +{ + float: right; +} + +#userViewForm fieldset +{ + border: 2px solid rgb(200, 200, 200); + width: 25em; + padding: 1em; +} + +#user-create_edit fieldset +{ + border: 2px solid rgb(200, 200, 200); + width: 33em; + padding: 1em; +} + +#useredit fieldset +{ + border: 2px solid rgb(200, 200, 200); + width: 36em; + padding: 1em; +} + +#userViewForm fieldset legend, #user-create_edit fieldset legend, #useredit fieldset legend +{ + padding: 0 0.5em; + color: rgb(85, 85, 85); +} + +input[type="submit"].active +{ + background: #009DCE !important; + background: -moz-linear-gradient(top, #009DCE 0%, #007EA5 100%) !important; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#009DCE), color-stop(100%,#007EA5)) !important; + background: -webkit-linear-gradient(top, #009DCE 0%,#007EA5 100%) !important; + background: -o-linear-gradient(top, #009DCE 0%,#007EA5 100%) !important; + background: -ms-linear-gradient(top, #009DCE 0%,#007EA5 100%) !important; + background: linear-gradient(top, #009DCE 0%,#007EA5 100%) !important; + color: #fff !important; + text-shadow: none !important; + border: 1px solid #007EA5 !important; +} + +input[type="submit"].active[disabled],input[type="submit"].active[disabled="disabled"],input[type="submit"].active[disabled="true"], +input[type="submit"].active[disabled]:hover,input[type="submit"].active[disabled="disabled"]:hover,input[type="submit"].active[disabled="true"]:hover +{ + background: #eeeeee !important; + background: -moz-linear-gradient(top, #eeeeee 0%, #eeeeee 100%) !important; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#eeeeee), color-stop(100%,#eeeeee)) !important; + background: -webkit-linear-gradient(top, #eeeeee 0%,#eeeeee 100%) !important; + background: -o-linear-gradient(top, #eeeeee 0%,#eeeeee 100%) !important; + background: -ms-linear-gradient(top, #eeeeee 0%,#eeeeee 100%) !important; + background: linear-gradient(top, #eeeeee 0%,#eeeeee 100%) !important; + color: #bbb !important; + border: 1px solid #E0E3E5 !important; + text-shadow: 0 2px 3px #FFFFFF !important; + cursor: default; +} + Property changes on: user-tool/tool/src/webapp/css/sakai-user-tool.css ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: user-tool/tool/src/webapp/js/userCreateValidation.js =================================================================== --- user-tool/tool/src/webapp/js/userCreateValidation.js (revision 0) +++ user-tool/tool/src/webapp/js/userCreateValidation.js (working copy) @@ -0,0 +1,116 @@ +/****************************************************************************** + * $URL$ + * $Id$ + ****************************************************************************** + * + * Copyright (c) 2003-2014 The Apereo Foundation + * + * Licensed under the Educational Community License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/ecl2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ +// USER declared in userValidationCommon.js + +// Validate the password from the form +USER.validatePassword = function () { + var username = USER.trim(USER.get("eid").value); + var pw = USER.get("pw").value; + var strongMsg = USER.get("strongMsg"); + var moderateMsg = USER.get("moderateMsg"); + var weakMsg = USER.get("weakMsg"); + var failMsg = USER.get("failMsg"); + var strengthInfo = USER.get("strengthInfo"); + var strengthBar = USER.get("strengthBar"); + var strengthBarMeter = USER.get("strengthBarMeter"); + + // If the password field has a value: + // 1) make the AJAX call to the validate password REST endpoint + // 2) conditionally display the appropriate messages + // 3) conditionally hide/show the strength info message + if (USER.isPasswordPolicyEnabled && pw.length > 0) { + USER.validatePasswordREST(pw, username); + USER.displayMessages(strongMsg, moderateMsg, weakMsg, failMsg, strengthBar, strengthBarMeter); + USER.displayStrengthInfo(); + } + + // Otherwise, password policy is disabled OR the password field has no value + else { + USER.passwordValid = pw.length > 0; + USER.hideAllElements(strongMsg, moderateMsg, weakMsg, failMsg, strengthInfo, strengthBar, strengthBarMeter); + } + + // Verify the passwords match (which in turn validates the form) + USER.verifyPasswordsMatch(); +}; + +// Verify the passwords match +USER.verifyPasswordsMatch = function () { + var pw = USER.get("pw").value; + var pw2 = USER.get("pw0").value; + var matchMsg = USER.get("matchMsg"); + var noMatchMsg = USER.get("noMatchMsg"); + + USER.passwordsMatch = pw === pw2; + if (pw.length > 0 || pw2.length > 0) { + USER.display(matchMsg, USER.passwordsMatch); + USER.display(noMatchMsg, !USER.passwordsMatch); + } + else { + USER.display(matchMsg, false); + USER.display(noMatchMsg, false); + } + + USER.validateForm(); +} + +// Validate the user ID from the form +USER.validateUserId = function () { + var userId = USER.trim(USER.get("eid").value); + USER.userValid = userId.length > 0; + USER.validatePassword(); +}; + +// Validate the email address from the form +USER.validateEmail = function () { + var email = USER.trim(USER.get("email").value); + var emailWarningMsg = USER.get("emailWarningMsg"); + + if (email.length < 1) { + USER.emailValid = true; + } + else { + USER.emailValid = USER.checkEmail(email); + } + + USER.display(emailWarningMsg, !USER.emailValid); + USER.validateForm(); +}; + +// Validate the form (enable/disable the submit button) +USER.validateForm = function () { + var submitButton = USER.get("eventSubmit_doSave"); + + if (USER.userValid && USER.emailValid && USER.passwordValid && USER.passwordsMatch) { + submitButton.disabled = false; + } + else { + submitButton.disabled = true; + } + + setMainFrameHeightNow(window.name); +}; + +// Initialization function +jQuery(document).ready(function () { + USER.validateEmail(); + USER.validateUserId(); +}); Property changes on: user-tool/tool/src/webapp/js/userCreateValidation.js ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +Date Revision Author HeadURL Id \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: user-tool/tool/src/webapp/js/userEditValidation.js =================================================================== --- user-tool/tool/src/webapp/js/userEditValidation.js (revision 0) +++ user-tool/tool/src/webapp/js/userEditValidation.js (working copy) @@ -0,0 +1,167 @@ +/****************************************************************************** + * $URL$ + * $Id$ + ****************************************************************************** + * + * Copyright (c) 2003-2014 The Apereo Foundation + * + * Licensed under the Educational Community License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/ecl2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ +// USER declared in userValidationCommon.js + +// Validate the user ID from the form +USER.validateUserId = function () { + var eid = USER.get("eid"); + var userIdReq = USER.get("userIdRequired"); + USER.userValid = false; + if (eid === null || userIdReq === null || USER.trim(eid.value).length > 0) { + USER.userValid = true; + } + + USER.validatePassword(); +} + +// Validate the password from the form +USER.validatePassword = function () { + var strongMsg = USER.get("strongMsg"); + var moderateMsg = USER.get("moderateMsg"); + var weakMsg = USER.get("weakMsg"); + var failMsg = USER.get("failMsg"); + var strengthInfo = USER.get("strengthInfo"); + var strengthBar = USER.get("strengthBar"); + var strengthBarMeter = USER.get("strengthBarMeter"); + var pw = USER.get("pw"); + + // If there's a password field and the password policy is enabled, get the password valud and the user ID + if (pw !== null && USER.isPasswordPolicyEnabled) { + var pass = pw.value; + var eid = USER.get("eid"); + var eidValue = USER.get("eidValue"); + var username = ""; + if (eid !== null) { + username = USER.trim(eid.value); + } + else if (eidValue !== null) { + username = eidValue.innerHTML; + } + + // If the password field has a value: + // 1) make the AJAX call to the validate password REST endpoint + // 2) conditionally display the appropriate messages + // 3) conditionally hide/show the strength info message + if (pass.length > 0) { + USER.validatePasswordREST(pass, username); + USER.displayMessages(strongMsg, moderateMsg, weakMsg, failMsg, strengthBar, strengthBarMeter); + USER.displayStrengthInfo(); + } + + // Password field has no value, hide all messages + else { + USER.hideAllElements(strongMsg, moderateMsg, weakMsg, failMsg, strengthInfo, strengthBar, strengthBarMeter); + } + } + + // There is no password field or the password policy is disabled, mark the password as valid and hide all messages + else { + USER.hideAllElements(strongMsg, moderateMsg, weakMsg, failMsg, strengthInfo, strengthBar, strengthBarMeter); + USER.passwordValid = true; + } + + // Verify the passwords match (which in turn validates the form) + USER.verifyPasswordsMatch(); +}; + +// Verify the passwords match +USER.verifyPasswordsMatch = function () { + var pw = USER.get("pw"); + var pw0 = USER.get("pw0"); + var matchMsg = USER.get("matchMsg"); + var noMatchMsg = USER.get("noMatchMsg"); + USER.passwordsMatch = false; + + if (pw !== null) { + var pass = pw.value; + var verPass = pw0.value; + USER.passwordsMatch = pass === verPass; + + if (pass.length > 0 || verPass.length > 0) { + USER.display(matchMsg, USER.passwordsMatch); + USER.display(noMatchMsg, !USER.passwordsMatch); + } + else { + USER.display(matchMsg, false); + USER.display(noMatchMsg, false); + } + } + else { + USER.passwordsMatch = true; + } + + USER.validateForm(); +}; + +// Validate the email address from the form +USER.validateEmail = function () { + USER.emailValid = false; + var email = USER.get("email"); + + if (email === null) { + USER.emailValid = true; + } + else { + var address = USER.trim(email.value); + + if (address.length < 1) { + USER.emailValid = true; + } + else { + USER.emailValid = USER.checkEmail(address); + } + } + + USER.display(emailWarningMsg, !USER.emailValid); + USER.validateForm(); +}; + +// Validate the current password from the form +USER.validateCurrentPassword = function () { + var pwcur = USER.get("pwcur"); + USER.currentPassValid = true; + if (pwcur !== null) { + USER.currentPassValid = pwcur.value.length > 0; + } + + USER.validateForm(); +}; + +// Validate the form (enabled/disable the submit button) +USER.validateForm = function () { + var submitButton = USER.get("eventSubmit_doSave"); + + if (USER.userValid && USER.passwordsMatch && USER.emailValid && (USER.isSuperUser || (USER.passwordValid && USER.currentPassValid))) { + submitButton.disabled = false; + } + else { + submitButton.disabled = true; + } + + setMainFrameHeightNow(window.name); +}; + +// Initialization function +jQuery(document).ready(function () { + USER.validateEmail(); + USER.validateCurrentPassword(); + USER.validateUserId(); +}); Property changes on: user-tool/tool/src/webapp/js/userEditValidation.js ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +Date Revision Author HeadURL Id \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: user-tool/tool/src/webapp/js/userValidationCommon.js =================================================================== --- user-tool/tool/src/webapp/js/userValidationCommon.js (revision 0) +++ user-tool/tool/src/webapp/js/userValidationCommon.js (working copy) @@ -0,0 +1,148 @@ +/****************************************************************************** + * $URL$ + * $Id$ + ****************************************************************************** + * + * Copyright (c) 2003-2014 The Apereo Foundation + * + * Licensed under the Educational Community License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/ecl2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *****************************************************************************/ +// 'Namespace' +var USER = {}; + +// Variables +USER.emailValid = false; +USER.userValid = false; +USER.passwordValid = false; +USER.currentPassValid = false; +USER.passwordWeak = false; +USER.passwordModerate = false; +USER.passwordStrong = false; +USER.passwordsMatch = false; +USER.isPasswordPolicyEnabled = false; + +// Get an element by ID +USER.get = function (id) { + return document.getElementById(id); +}; + +// Trim leading and trailing whitespace from the given string +USER.trim = function (inputString) { + return inputString.replace(/^\s+|\s+$/g, ""); +}; + +// Show/hide the given element +USER.display = function (element, show) { + if (show) { + element.style.display = "block"; + } + else { + element.style.display = "none"; + } +} + +// Validate the given email address string +USER.checkEmail = function (email) { + if (!email || email.length < 5) { + return false; + } + + var simpleRegexForEmail = /\S+@\S+\.\S\S+/; + return simpleRegexForEmail.test(email); +} + +// Conditionally hide/show the strength info message +USER.displayStrengthInfo = function () { + if (USER.isPasswordPolicyEnabled) { + var showStrengthInfo = false; + var strengthInfo = USER.get("strengthInfo"); + var passField = USER.get("pw"); + if (passField !== null && passField.value.length > 0) { + if (!USER.passwordValid || (!USER.passwordStrong && passField === document.activeElement)) { + showStrengthInfo = true; + } + } + + USER.display(strengthInfo, showStrengthInfo); + } +} + +// Make the AJAX call to the validate password REST endpoint +USER.validatePasswordREST = function (password, username) { + jQuery.ajax({ + url: "/direct/user/validatePassword", + type: "POST", + data: "password=" + password + "&username=" + username, + async: false, + success: function (data) { + USER.passwordValid = false; + USER.passwordWeak = false; + USER.passwordModerate = false; + USER.passwordStrong = false; + + if ("WEAK" === data) { + USER.passwordValid = true; + USER.passwordWeak = true; + } + else if ("MODERATE" === data) { + USER.passwordValid = true; + USER.passwordModerate = true; + } + else if ("STRONG" === data) { + USER.passwordValid = true; + USER.passwordStrong = true; + } + } + }); +} + +// Display the appropriate messages based on the current password valid and strength status +USER.displayMessages = function (strongMsg, moderateMsg, weakMsg, failMsg, strengthBar, strengthBarMeter) { + USER.display(strongMsg, USER.passwordStrong); + USER.display(moderateMsg, USER.passwordModerate); + USER.display(weakMsg, USER.passwordWeak); + USER.display(failMsg, !USER.passwordValid); + + if (USER.passwordStrong) { + strengthBarMeter.style.width = "100%"; + strengthBarMeter.style.backgroundColor = "#178c0b"; + } + else if (USER.passwordModerate) { + strengthBarMeter.style.width = "66%"; + strengthBarMeter.style.backgroundColor = "#edbc03"; + } + else if (USER.passwordWeak) { + strengthBarMeter.style.width = "33%"; + strengthBarMeter.style.backgroundColor = "#900"; + } + else { + strengthBarMeter.style.width = "0%"; + strengthBarMeter.style.backgroundColor = "#900"; + } + + var showStrengthBar = (USER.passwordStrong || USER.passwordModerate || USER.passwordWeak || !USER.passwordValid); + USER.display(strengthBar, showStrengthBar); + USER.display(strengthBarMeter, showStrengthBar); +} + +// Hide all password policy related messages +USER.hideAllElements = function (strongMsg, moderateMsg, weakMsg, failMsg, strengthInfo, strengthBar, strengthBarMeter) { + USER.display(strongMsg, false); + USER.display(moderateMsg, false); + USER.display(weakMsg, false); + USER.display(failMsg, false); + USER.display(strengthInfo, false); + USER.display(strengthBar, false); + USER.display(strengthBarMeter, false); +} Property changes on: user-tool/tool/src/webapp/js/userValidationCommon.js ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +Date Revision Author HeadURL Id \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: user-tool/tool/src/webapp/vm/user/chef_users_create.vm =================================================================== --- user-tool/tool/src/webapp/vm/user/chef_users_create.vm (revision 308072) +++ user-tool/tool/src/webapp/vm/user/chef_users_create.vm (working copy) @@ -1,8 +1,14 @@ ## $Header: /cvs/sakai2/legacy/tools/src/webapp/vm/admin/chef_users_create.vm,v 1.2 2005/05/24 19:36:12 gsilver.umich.edu Exp $ + + + + + +
#if($menu) @@ -12,60 +18,76 @@

$tlang.getString("usecre.entthe")

-

* $tlang.getString("usecre.instruc")

- + #if ($alertMessage)
$tlang.getString("useconrem.alert") $validator.escapeHtml($alertMessage)
#end -
-

- - #if(!$user)#else$validator.escapeHtml($user.Eid)#end -

-

- - -

-

- - -

-

- - -

-

- - -

-

- - -

-

- - - -

- $!recaptchaScript -
- - -
- + +
+ + $tlang.getString("usecre.creaco") + +
+ * $tlang.getString("usecre.instruc") +
+
+ + #if(!$user)#else$validator.escapeHtml($user.Eid)#end +
+
+ + +
+
+ + +
+
+ + + +
+
+ + + + + + + + +
+
+ + + + +
+
+ + + +
+ $!recaptchaScript +
+ + + +
- Index: user-tool/tool/src/webapp/vm/user/chef_users_edit.vm =================================================================== --- user-tool/tool/src/webapp/vm/user/chef_users_edit.vm (revision 308072) +++ user-tool/tool/src/webapp/vm/user/chef_users_edit.vm (working copy) @@ -1,5 +1,7 @@ ## $Header: /cvs/sakai2/legacy/tools/src/webapp/vm/admin/chef_users_edit.vm,v 1.2 2005/05/24 19:36:12 gsilver.umich.edu Exp $ + + @@ -32,6 +34,11 @@ + + + + +
#if($menu) #toolbar($menu) @@ -41,13 +48,19 @@

$tlang.getString("useedi.revandmod")

-

* $tlang.getString("usecre.instruc")

- - #if ($alertMessage)
$tlang.getString("useconrem.alert") $validator.escapeHtml($alertMessage)
#end -
-

+ + #if ($alertMessage)

$tlang.getString("useconrem.alert") $validator.escapeHtml($alertMessage)
#end + +
+ + #if($user) $tlang.getString("useedi.edit") #else $tlang.getString("usecre.creaco")#end + +
+ * $tlang.getString("usecre.instruc") +
+
#if($!user && !$valueEid) #set($valueEid=$user.Eid) @@ -54,18 +67,18 @@ #end #if(!$user) ## creating new account - + #else ## modifying existing account #if($!superUser) ## only admin type user can modify the eid field - + #else - $validator.escapeHtml($!valueEid) + $validator.escapeHtml($!valueEid) #end #end -

-

+

+
@@ -74,8 +87,8 @@ #else #if($user)$validator.escapeHtml($user.FirstName)#elseif($valueFirstName)$validator.escapeHtml($valueFirstName)#end #end -

-

+

+
@@ -84,53 +97,64 @@ #else #if($user)$validator.escapeHtml($user.LastName)#elseif($valueLastName)$validator.escapeHtml($valueLastName)#end #end -

-

+

+
#if ($service.allowUpdateUserEmail($user.Id) || !$user) - + + #else #if($user)$validator.escapeHtml($user.Email)#elseif($valueEmail)$validator.escapeHtml($valueEmail)#end #end -

+
#if ($incPw) #if(!$!superUser) -

+

#if ($service.allowUpdateUserName($user.Id) || $service.allowUpdateUserEmail($user.Id) || $service.allowUpdateUserPassword($user.Id) || !$user) - + #else   #end -

+
#end -

+

#if ($service.allowUpdateUserPassword($user.Id) || !$user) - + + + + + + + #else   #end -

-

+

+
#if ($service.allowUpdateUserPassword($user.Id) || !$user) - + + + #else   #end -

+
#end #if ($incType) -

+

@@ -147,10 +171,10 @@ #else #if($user)$validator.escapeHtml($user.Type)#elseif($valueType)$validator.escapeHtml($valueType)#end #end -

+
#end -

+

#set($disabled = $user.Properties.getProperty("disabled")) #if(!$!superUser) @@ -158,30 +182,30 @@ #else $tlang.getString("disable") #end -

+
#if ($user) -

+

$validator.escapeHtml($user.CreatedBy.DisplayName) -

-

+

+
$validator.escapeHtml($user.CreatedTime.toStringLocalFull()) -

-

+

+
$validator.escapeHtml($user.ModifiedBy.DisplayName) -

-

+

+
$validator.escapeHtml($user.ModifiedTime.toStringLocalFull()) -

-

+

+
$validator.escapeHtml($user.Id) -

+
#end ## optional attributes block @@ -215,13 +239,14 @@
#if($user) - + #else - + #end - +
+
Index: user-tool/tool/src/webapp/vm/user/chef_users_view.vm =================================================================== --- user-tool/tool/src/webapp/vm/user/chef_users_view.vm (revision 308072) +++ user-tool/tool/src/webapp/vm/user/chef_users_view.vm (working copy) @@ -1,5 +1,7 @@ ## $Header: /cvs/sakai2/legacy/tools/src/webapp/vm/admin/chef_users_view.vm,v 1.2 2005/05/24 19:36:12 gsilver.umich.edu Exp $ + +
#if($menu) #toolbar($menu) @@ -9,99 +11,66 @@ $tlang.getString("usevie.revandmod") #if ($alertMessage) -
- $tlang.getString("useconrem.alert") $validator.escapeHtml($alertMessage) -
+
+ $tlang.getString("useconrem.alert") $validator.escapeHtml($alertMessage) +
#end -
-

- $tlang.getString("usevie.use") -

- - - - - - - - - - - - - - - - - - - - - - -
- $tlang.getString("useconrem.useid") - - $validator.escapeHtml($user.Eid) -
- $tlang.getString("usecre.firnam") - - $validator.escapeHtml($user.FirstName) -
- $tlang.getString("usecre.lasnam") - - $validator.escapeHtml($user.LastName) -
- $tlang.getString("usevie.ema") - - $validator.escapeHtml($user.Email) -
- $tlang.getString("usecre.typ") - - $validator.escapeHtml($user.Type) -
+ +
+ + $tlang.getString("usevie.use") + +
+ + $validator.escapeHtml($user.Eid) +
+
+ + $validator.escapeHtml($user.FirstName) +
+
+ + $validator.escapeHtml($user.LastName) +
+
+ + $validator.escapeHtml($user.Email) +
+
+ + $validator.escapeHtml($user.Type) +
+ #if($enableEdit) - - - - - - - - - - - - - - - - - - - - - -
- $tlang.getString("disabled") - - #set($disabled = $user.Properties.getProperty("disabled")) - #if ($disabled != 'true')$tlang.getString("false") #else $tlang.getString("true") #end -
$tlang.getString("useedi.creby") - $validator.escapeHtml($user.CreatedBy.DisplayName) -
$tlang.getString("useedi.cre") - $validator.escapeHtml($user.CreatedTime.toStringLocalFull()) -
$tlang.getString("useedi.modby") - $validator.escapeHtml($user.ModifiedBy.DisplayName) -
$tlang.getString("useedi.mod") - $validator.escapeHtml($user.ModifiedTime.toStringLocalFull()) -
-
- -
+
+ + #set($disabled = $user.Properties.getProperty("disabled")) + #if ($disabled != 'true')$tlang.getString("false") #else $tlang.getString("true") #end +
+
+ + $validator.escapeHtml($user.CreatedBy.DisplayName) +
+
+ + $validator.escapeHtml($user.CreatedTime.toStringLocalFull()) +
+
+ + $validator.escapeHtml($user.ModifiedBy.DisplayName) +
+
+ + $validator.escapeHtml($user.ModifiedTime.toStringLocalFull()) +
+ +
+ +
#end - - + + +