From 509e2c420b33354283cbd771e494ed394ef88037 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Chitrank=20Dav=C3=A9?=
Date: Fri, 20 Dec 2024 20:24:16 -0500
Subject: [PATCH] Migrate password hashing to BCrypt using Spring Security
- Replaced SHA-1 hashing with BCryptPasswordEncoder for enhanced password security.
- Introduced PasswordHashHelper to centralize encoding logic, supporting both BCrypt and legacy SHA-1 hashes via DelegatingPasswordEncoder.
- Enhanced SecurityManager to handle password encoding, validation, and hash upgrades.
- Updated login and password management flows to utilize SecurityManager for secure handling.
- Refactored EncryptionUtils to delegate password hashing to PasswordHashHelper.
- Added spring-security-crypto to pom.xml for access to robust cryptography utilities.
Ensured compatibility with legacy hashes while enabling secure migration to BCrypt.
---
pom.xml | 7 +
.../web/admin/SecurityAddSecurityHelper.java | 23 +---
.../oscarehr/managers/SecurityManager.java | 100 +++++++++-----
.../org/oscarehr/util/EncryptionUtils.java | 33 +++--
.../Deprecated_SHA_PasswordEncoder.java | 77 +++++++++++
.../util/password/PasswordHashHelper.java | 124 ++++++++++++++++++
src/main/java/oscar/login/LoginAction.java | 38 ++----
.../java/oscar/login/LoginCheckLoginBean.java | 10 +-
.../provider/providerupdatepassword.jsp | 45 +++----
9 files changed, 333 insertions(+), 124 deletions(-)
create mode 100644 src/main/java/org/oscarehr/util/password/Deprecated_SHA_PasswordEncoder.java
create mode 100644 src/main/java/org/oscarehr/util/password/PasswordHashHelper.java
diff --git a/pom.xml b/pom.xml
index 49975d0f42..fc9303f4bf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1054,6 +1054,13 @@
1.78.1
+
+
+ org.springframework.security
+ spring-security-crypto
+ 5.8.16
+
+
diff --git a/src/main/java/com/quatro/web/admin/SecurityAddSecurityHelper.java b/src/main/java/com/quatro/web/admin/SecurityAddSecurityHelper.java
index b3625dedb3..2ce1a01bde 100644
--- a/src/main/java/com/quatro/web/admin/SecurityAddSecurityHelper.java
+++ b/src/main/java/com/quatro/web/admin/SecurityAddSecurityHelper.java
@@ -23,8 +23,6 @@
*/
package com.quatro.web.admin;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.Date;
import javax.servlet.ServletRequest;
@@ -32,7 +30,7 @@
import org.oscarehr.common.dao.SecurityDao;
import org.oscarehr.common.model.Security;
-import org.oscarehr.util.MiscUtils;
+import org.oscarehr.managers.SecurityManager;
import org.oscarehr.util.SpringUtils;
import oscar.MyDateFormat;
@@ -46,6 +44,7 @@
public class SecurityAddSecurityHelper {
private SecurityDao securityDao = SpringUtils.getBean(SecurityDao.class);
+ private final SecurityManager securityManager = SpringUtils.getBean(SecurityManager.class);
/**
* Adds a security record (i.e. user login information) for the provider.
@@ -60,26 +59,10 @@ public void addProvider(PageContext pageContext) {
pageContext.setAttribute("message", message);
}
- public static String digestPassword(String rawPassword) throws NoSuchAlgorithmException {
- StringBuilder sbTemp = new StringBuilder();
- MessageDigest md = MessageDigest.getInstance("SHA");
- byte[] btNewPasswd = md.digest(rawPassword.getBytes());
- for (int i = 0; i < btNewPasswd.length; i++)
- sbTemp = sbTemp.append(btNewPasswd[i]);
- return sbTemp.toString();
- }
-
private String process(PageContext pageContext) {
ServletRequest request = pageContext.getRequest();
- String digestedPassword = null;
-
- try {
- digestedPassword = digestPassword(request.getParameter("password"));
- } catch (NoSuchAlgorithmException e) {
- MiscUtils.getLogger().error("Unable to get SHA message digest", e);
- return "admin.securityaddsecurity.msgAdditionFailure";
- }
+ String digestedPassword = this.securityManager.encodePassword(request.getParameter("password"));
boolean isUserRecordAlreadyCreatedForProvider = !securityDao.findByProviderNo(request.getParameter("provider_no")).isEmpty();
if (isUserRecordAlreadyCreatedForProvider) return "admin.securityaddsecurity.msgLoginAlreadyExistsForProvider";
diff --git a/src/main/java/org/oscarehr/managers/SecurityManager.java b/src/main/java/org/oscarehr/managers/SecurityManager.java
index 7d4c98244b..76b88a91f2 100644
--- a/src/main/java/org/oscarehr/managers/SecurityManager.java
+++ b/src/main/java/org/oscarehr/managers/SecurityManager.java
@@ -23,26 +23,26 @@
*/
package org.oscarehr.managers;
-import java.security.MessageDigest;
-import java.util.Date;
-import java.util.List;
-
import org.apache.cxf.common.util.StringUtils;
+import org.apache.logging.log4j.Logger;
import org.oscarehr.common.dao.SecurityArchiveDao;
import org.oscarehr.common.dao.SecurityDao;
import org.oscarehr.common.model.Security;
+import org.oscarehr.util.EncryptionUtils;
import org.oscarehr.util.LoggedInInfo;
import org.oscarehr.util.MiscUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-
import oscar.OscarProperties;
import oscar.log.LogAction;
+import java.util.Date;
+import java.util.List;
+
@Service
public class SecurityManager {
- //private static Logger logger = MiscUtils.getLogger();
+ private static final Logger logger = MiscUtils.getLogger();
@Autowired
private SecurityDao securityDao;
@@ -85,8 +85,8 @@ public boolean checkPasswordAgainstPrevious(String newPassword, String providerN
String previousPasswordPolicy = OscarProperties.getInstance().getProperty("password.pastPasswordsToNotUse", "0");
try {
Security dbSecurity = securityDao.getByProviderNo(providerNo);
-
- if(!"0".equals(previousPasswordPolicy) && !validatePassword(newPassword, dbSecurity.getPassword())) {
+
+ if (!"0".equals(previousPasswordPolicy) && !this.matchesPassword(newPassword, dbSecurity.getPassword())) {
int numToGoBack = Integer.parseInt(previousPasswordPolicy);
List archives = securityArchiveDao.findPreviousPasswordsByProviderNo(providerNo,numToGoBack);
@@ -94,7 +94,7 @@ public boolean checkPasswordAgainstPrevious(String newPassword, String providerN
boolean foundItInPast=false;
for(String a:archives) {
- if(validatePassword(newPassword, a)) {
+ if (this.matchesPassword(newPassword, a)) {
foundItInPast = true;
break;
}
@@ -110,34 +110,64 @@ public boolean checkPasswordAgainstPrevious(String newPassword, String providerN
}
return false;
}
-
- private boolean validatePassword(String newPassword, String existingPassword) {
-
- try {
- String p1 = encodePassword(newPassword);
- if(p1.equals(existingPassword)) {
- return true;
- }
- } catch(Exception e) {
- MiscUtils.getLogger().error("Error",e);
+
+ /**
+ * Encode the given password using the configured hashing algorithm.
+ *
+ * @param password The password to encrypt.
+ * @return The encrypted password.
+ */
+ public String encodePassword(CharSequence password) {
+ return EncryptionUtils.hash(password);
+ }
+
+ /**
+ * Validates the password against the provided security's stored password. If the password is valid and an upgrade
+ * is needed to the existing stored password, the stored password will be upgraded.
+ *
+ * @param rawPassword The password to validate.
+ * @param security The security object containing the stored password.
+ */
+ public boolean validatePassword(CharSequence rawPassword, Security security) {
+ boolean isValid = this.matchesPassword(rawPassword, security.getPassword());
+ if (isValid && EncryptionUtils.isPasswordHashUpgradeNeeded(security.getPassword())) {
+ boolean isHashUpgraded = this.upgradeSavePasswordHash(rawPassword, security);
+ if (isHashUpgraded)
+ logger.error("Error while upgrading password hash");
}
-
- return false;
+ return isValid;
+ }
+
+ /**
+ * Validates the password against the provided encoded password.
+ *
+ * @param rawPassword The password to validate.
+ * @param encodedPassword The encoded password to compare against.
+ * @return True if the password is valid, false otherwise.
+ */
+ public boolean matchesPassword(CharSequence rawPassword, String encodedPassword) {
+ return EncryptionUtils.verify(rawPassword, encodedPassword);
+ }
+
+ /**
+ * Upgrades the password hash and saves the updated Security object.
+ *
+ * @param rawPassword The raw password to hash.
+ * @param security The Security object to update.
+ * @return True if the password hash was successfully upgraded and saved, false otherwise.
+ */
+ public boolean upgradeSavePasswordHash(CharSequence rawPassword, Security security) {
+ String hash = this.encodePassword(rawPassword);
+ boolean matched = this.matchesPassword(rawPassword, hash);
+
+ if (!matched) // should never happen, but if password upgrade fails.
+ return false;
+
+ security.setPassword(hash);
+ this.securityDao.merge(security);
+ return true;
}
-
- private String encodePassword(String password) throws Exception{
- MessageDigest md = MessageDigest.getInstance("SHA");
-
- StringBuilder sbTemp = new StringBuilder();
- byte[] btNewPasswd= md.digest(password.getBytes());
- for(int i=0; i results = securityDao.findByProviderNo(providerNo);
@@ -250,4 +280,4 @@ protected boolean isSecurityObjectValid(Security security) {
return true;
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/oscarehr/util/EncryptionUtils.java b/src/main/java/org/oscarehr/util/EncryptionUtils.java
index 10130baae8..ef0e45ebb2 100644
--- a/src/main/java/org/oscarehr/util/EncryptionUtils.java
+++ b/src/main/java/org/oscarehr/util/EncryptionUtils.java
@@ -24,6 +24,7 @@
package org.oscarehr.util;
import org.apache.logging.log4j.Logger;
+import org.oscarehr.util.password.PasswordHashHelper;
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
@@ -35,7 +36,7 @@
import java.util.Objects;
-public final class EncryptionUtils extends PasswordHash {
+public final class EncryptionUtils {
private static final QueueCacheValueCloner byteArrayCloner = new QueueCacheValueCloner() {
public byte[] cloneBean(byte[] original) {
return (byte[])original.clone();
@@ -283,25 +284,39 @@ public static void prepareSecretKeySpec() {
}
/**
- * A one way PBKDF2 With Hmac SHA1 hash of given password string.
- * The verify method, should be used to validate the hash against
- * passwords.
+ * Generates a secure hash of the given password using the PasswordHashHelper.
+ *
+ * @see PasswordHashHelper#encodePassword(CharSequence)
* @param password string
* @return hashed password
- * @throws CannotPerformOperationException failed encrypt
+ * @throws IllegalArgumentException If the password is null or empty.
*/
- public static String hash(String password) throws CannotPerformOperationException {
- return createHash(password);
+ public static String hash(CharSequence password) throws IllegalArgumentException {
+ return PasswordHashHelper.encodePassword(password);
}
/**
* Validate a given password phrase against the stored hash password.
* This is a boolean validation. No password values are returned
* @param password plain password string
+ * @see PasswordHashHelper#matches(CharSequence, String)
+ * @param hashedPassword hashed password string usually stored in the database.
+ * @return True if the raw password matches the encoded password, false otherwise.
+ * @throws IllegalArgumentException failure while matching
+ */
+ public static boolean verify(CharSequence password, String hashedPassword) throws IllegalArgumentException {
+ return PasswordHashHelper.matches(password, hashedPassword);
+ }
+
+ /**
+ * Check if a given hashed password needs to be upgraded to a more secure
+ * algorithm.
* @param hashedPassword hashed password string usually stored in the database.
+ * @see PasswordHashHelper#upgradeEncoding(String)
+ * @return true if upgrade is needed.
*/
- public static boolean verify(String password, String hashedPassword) throws InvalidHashException, CannotPerformOperationException {
- return verifyPassword(password, hashedPassword);
+ public static boolean isPasswordHashUpgradeNeeded(String hashedPassword) {
+ return PasswordHashHelper.upgradeEncoding(hashedPassword);
}
static {
diff --git a/src/main/java/org/oscarehr/util/password/Deprecated_SHA_PasswordEncoder.java b/src/main/java/org/oscarehr/util/password/Deprecated_SHA_PasswordEncoder.java
new file mode 100644
index 0000000000..e5ecfe4d76
--- /dev/null
+++ b/src/main/java/org/oscarehr/util/password/Deprecated_SHA_PasswordEncoder.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2005-2012. Centre for Research on Inner City Health, St. Michael's Hospital, Toronto. All Rights Reserved.
+ * This software is published under the GPL GNU General Public License.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This software was written for
+ * Centre for Research on Inner City Health, St. Michael's Hospital,
+ * Toronto, Ontario, Canada
+ */
+
+package org.oscarehr.util.password;
+
+
+import org.oscarehr.util.MiscUtils;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import java.security.MessageDigest;
+
+
+/**
+ * This class uses insecure SHA hashing for backwards compatibility while migrating to a newer hashing method.
+ * It will be removed in the future.
+ */
+public class Deprecated_SHA_PasswordEncoder implements PasswordEncoder {
+
+ @Override
+ public String encode(CharSequence rawPassword) {
+ try {
+ return this.encodeShaPassword(rawPassword.toString());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean matches(CharSequence rawPassword, String encodedPassword) {
+ return this.validateShaPassword(rawPassword.toString(), encodedPassword);
+ }
+
+ private boolean validateShaPassword(String newPassword, String existingPassword) {
+
+ try {
+ String p1 = this.encodeShaPassword(newPassword);
+ if (p1.equals(existingPassword)) {
+ return true;
+ }
+ } catch (Exception e) {
+ MiscUtils.getLogger().error("Error", e);
+ }
+
+ return false;
+ }
+
+ private String encodeShaPassword(String password) throws Exception {
+
+ MessageDigest md = MessageDigest.getInstance("SHA");
+
+ StringBuilder sbTemp = new StringBuilder();
+ byte[] btNewPasswd = md.digest(password.getBytes());
+ for (int i = 0; i < btNewPasswd.length; i++) sbTemp = sbTemp.append(btNewPasswd[i]);
+
+ return sbTemp.toString();
+
+ }
+}
diff --git a/src/main/java/org/oscarehr/util/password/PasswordHashHelper.java b/src/main/java/org/oscarehr/util/password/PasswordHashHelper.java
new file mode 100644
index 0000000000..8b1a78ddd7
--- /dev/null
+++ b/src/main/java/org/oscarehr/util/password/PasswordHashHelper.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) 2005-2012. Centre for Research on Inner City Health, St. Michael's Hospital, Toronto. All Rights Reserved.
+ * This software is published under the GPL GNU General Public License.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This software was written for
+ * Centre for Research on Inner City Health, St. Michael's Hospital,
+ * Toronto, Ontario, Canada
+ */
+
+package org.oscarehr.util.password;
+
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * A helper class for password hashing using Spring Security's password encoder.
+ *
+ * @see org.springframework.security.crypto.password.PasswordEncoder
+ * @see
+ * Spring Security Password Storage Documentation
+ */
+public class PasswordHashHelper {
+
+ private static final PasswordEncoder PASSWORD_ENCODER = PasswordHashHelper.getDelegatingPasswordEncoder();
+
+ /**
+ * Creates a {@link DelegatingPasswordEncoder} with default mappings.
+ * Additional mappings may be added and the encoding will be updated to conform with best practices.
+ * However, due to the nature of {@link DelegatingPasswordEncoder} the updates should not impact users.
+ * The mappings current are:
+ *
+ * - bcrypt - BCryptPasswordEncoder (Default for encoding)
+ * - null (SHA) - Deprecated_SHA_PasswordEncoder (Old deprecated encoding)
+ *
+ *
+ * The {@link DelegatingPasswordEncoder} allows for encoding passwords using various algorithms,
+ * determined by prefixes in the encoded password string.
+ *
+ *
+ *
+ * Prior to Spring Security 5.0, the default PasswordEncoder was NoOpPasswordEncoder, which required plain-text passwords.
+ * Based on the Password History section, you might expect that the default PasswordEncoder would now be something like BCryptPasswordEncoder.
+ * However, this ignores three real world problems:
+ *
+ * - Many applications use old password encodings that cannot easily migrate.
+ * - The best practice for password storage will change again.
+ * - As a framework, Spring Security cannot make breaking changes frequently.
+ *
+ * Instead, Spring Security introduces {@link DelegatingPasswordEncoder}, which solves all the problems by:
+ *
+ * - Ensuring that passwords are encoded by using the current password storage recommendations
+ * - Allowing for validating passwords in modern and legacy formats
+ * - Allowing for upgrading the encoding in the future
+ *
+ *
+ * @see
+ * Reference Documentation
+ *
+ * @return the {@link PasswordEncoder} to use
+ */
+
+ private static PasswordEncoder getDelegatingPasswordEncoder() {
+ String encodingId = "bcrypt";
+ Map encoders = new HashMap<>();
+
+ encoders.put("bcrypt", new BCryptPasswordEncoder());
+ encoders.put(null, new Deprecated_SHA_PasswordEncoder());
+
+ return new DelegatingPasswordEncoder(encodingId, encoders);
+ }
+
+ /**
+ * Encodes a raw password using the configured {@code PASSWORD_ENCODER}.
+ *
+ * @param rawPassword The raw password to encode. Cannot be null.
+ * @return The encoded password string.
+ * @throws IllegalArgumentException If the rawPassword is null.
+ */
+ public static String encodePassword(CharSequence rawPassword) throws IllegalArgumentException {
+ return PASSWORD_ENCODER.encode(rawPassword);
+ }
+
+ /**
+ * Checks if a raw password matches an encoded password using the configured {@code PASSWORD_ENCODER}.
+ *
+ * @param rawPassword The raw password to check. Cannot be null.
+ * @param encodedPassword The encoded password to compare against. Cannot be null.
+ * @return True if the raw password matches the encoded password, false otherwise.
+ * @throws IllegalArgumentException if either rawPassword or encodedPassword is null.
+ */
+ public static boolean matches(CharSequence rawPassword, String encodedPassword) throws IllegalArgumentException {
+ return PASSWORD_ENCODER.matches(rawPassword, encodedPassword);
+ }
+
+ /**
+ * Determines if a given encoded password requires updating to the current hashing algorithm.
+ *
+ * @param encodedPassword The encoded password to upgrade. Cannot be null.
+ * @return True if the password was upgraded, false otherwise.
+ * @throws IllegalArgumentException if encodedPassword is null.
+ */
+ public static boolean upgradeEncoding(String encodedPassword) {
+ return PASSWORD_ENCODER.upgradeEncoding(encodedPassword);
+ }
+
+}
diff --git a/src/main/java/oscar/login/LoginAction.java b/src/main/java/oscar/login/LoginAction.java
index 6dd1a7ffc1..a98b4ba7e4 100644
--- a/src/main/java/oscar/login/LoginAction.java
+++ b/src/main/java/oscar/login/LoginAction.java
@@ -40,6 +40,7 @@
import org.oscarehr.common.model.*;
import org.oscarehr.decisionSupport.service.DSService;
import org.oscarehr.managers.AppManager;
+import org.oscarehr.managers.SecurityManager;
import org.oscarehr.util.*;
import org.owasp.encoder.Encode;
import org.springframework.context.ApplicationContext;
@@ -56,7 +57,6 @@
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
-import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -83,6 +83,8 @@ public final class LoginAction extends DispatchAction {
private ProviderDao providerDao = SpringUtils.getBean(ProviderDao.class);
private UserPropertyDAO propDao = SpringUtils.getBean(UserPropertyDAO.class);
+ private final SecurityManager securityManager = SpringUtils.getBean(SecurityManager.class);
+
// remove after testing is done
// private SsoAuthenticationManager ssoAuthenticationManager =
// SpringUtils.getBean(SsoAuthenticationManager.class);
@@ -151,8 +153,7 @@ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServlet
String oldPassword = ((LoginForm) form).getOldPassword();
try {
- String errorStr = errorHandling(password, newPassword, confirmPassword, encodePassword(oldPassword),
- oldPassword);
+ String errorStr = errorHandling(password, newPassword, confirmPassword, oldPassword);
// Error Handling
if (errorStr != null && !errorStr.isEmpty()) {
@@ -609,7 +610,7 @@ private void removeAttributesFromSession(HttpServletRequest request) {
private void setUserInfoToSession(HttpServletRequest request, String userName, String password, String pin,
String nextPage) throws Exception {
request.getSession().setAttribute("userName", userName);
- request.getSession().setAttribute("password", encodePassword(password));
+ request.getSession().setAttribute("password", this.securityManager.encodePassword(password));
request.getSession().setAttribute("pin", pin);
request.getSession().setAttribute("nextPage", nextPage);
@@ -618,18 +619,18 @@ private void setUserInfoToSession(HttpServletRequest request, String userName, S
/**
* Performs the error handling
*
- * @param password
+ * @param oldEncodedPassword
* @param newPassword
* @param confirmPassword
* @param oldPassword
* @return
*/
- private String errorHandling(String password, String newPassword, String confirmPassword, String encodedOldPassword,
+ private String errorHandling(String oldEncodedPassword, String newPassword, String confirmPassword,
String oldPassword) {
String newURL = "";
- if (!encodedOldPassword.equals(password)) {
+ if (!this.securityManager.matchesPassword(oldPassword, oldEncodedPassword)) {
newURL = newURL
+ "?errormsg=Your old password, does NOT match the password in the system. Please enter your old password.";
} else if (!newPassword.equals(confirmPassword)) {
@@ -639,30 +640,9 @@ private String errorHandling(String password, String newPassword, String confirm
newURL = newURL
+ "?errormsg=Your new password, is the same as your old password. Please choose a new password.";
}
-
return newURL;
}
- /**
- * This method encodes the password, before setting to session.
- *
- * @param password
- * @return
- * @throws Exception
- */
- private String encodePassword(String password) throws Exception {
-
- MessageDigest md = MessageDigest.getInstance("SHA");
-
- StringBuilder sbTemp = new StringBuilder();
- byte[] btNewPasswd = md.digest(password.getBytes());
- for (int i = 0; i < btNewPasswd.length; i++)
- sbTemp = sbTemp.append(btNewPasswd[i]);
-
- return sbTemp.toString();
-
- }
-
/**
* get the security record based on the username
*
@@ -696,7 +676,7 @@ private Security getSecurity(String username) {
private void persistNewPassword(String userName, String newPassword) throws Exception {
Security security = getSecurity(userName);
- security.setPassword(encodePassword(newPassword));
+ security.setPassword(this.securityManager.encodePassword(newPassword));
security.setForcePasswordReset(Boolean.FALSE);
SecurityDao securityDao = (SecurityDao) SpringUtils.getBean(SecurityDao.class);
securityDao.saveEntity(security);
diff --git a/src/main/java/oscar/login/LoginCheckLoginBean.java b/src/main/java/oscar/login/LoginCheckLoginBean.java
index 6634d544ed..4cb65b0702 100644
--- a/src/main/java/oscar/login/LoginCheckLoginBean.java
+++ b/src/main/java/oscar/login/LoginCheckLoginBean.java
@@ -35,6 +35,7 @@
import org.oscarehr.common.dao.SecurityDao;
import org.oscarehr.common.model.Provider;
import org.oscarehr.common.model.Security;
+import org.oscarehr.managers.SecurityManager;
import org.oscarehr.util.MiscUtils;
import org.oscarehr.util.SSOUtility;
import org.oscarehr.util.SpringUtils;
@@ -48,6 +49,8 @@ public final class LoginCheckLoginBean {
private static final Logger logger = MiscUtils.getLogger();
private static final String LOG_PRE = "Login!@#$: ";
+ private final SecurityManager securityManager = SpringUtils.getBean(SecurityManager.class);
+
private String username = "";
private String password = "";
private String pin;
@@ -128,8 +131,13 @@ public String[] authenticate() {
userpassword = security.getPassword();
if (userpassword.length() < 20) {
auth = password.equals(userpassword);
+ if (auth) {
+ boolean isPasswordUpgraded = this.securityManager.upgradeSavePasswordHash(this.password, this.security);
+ if (!isPasswordUpgraded)
+ logger.error("Error while upgrading password hash");
+ }
} else {
- auth = security.checkPassword(password);
+ auth = this.securityManager.validatePassword(this.password, this.security);
}
if (auth) { // login successfully
diff --git a/src/main/webapp/provider/providerupdatepassword.jsp b/src/main/webapp/provider/providerupdatepassword.jsp
index b84a563a83..2859ea2b0b 100644
--- a/src/main/webapp/provider/providerupdatepassword.jsp
+++ b/src/main/webapp/provider/providerupdatepassword.jsp
@@ -28,7 +28,6 @@
if(session.getValue("user") == null)
response.sendRedirect("../logout.jsp");
String curUser_no = (String) session.getAttribute("user");
- MessageDigest md = MessageDigest.getInstance("SHA");
%>
<%@ page
@@ -44,7 +43,7 @@
<%@ page import="org.oscarehr.phr.util.MyOscarUtils" %>
<%
LoggedInInfo loggedInInfo = LoggedInInfo.getLoggedInInfoFromSession(request);
- org.oscarehr.managers.SecurityManager securityManager = SpringUtils.getBean(org.oscarehr.managers.SecurityManager.class);
+ SecurityManager securityManager = SpringUtils.getBean(SecurityManager.class);
%>
<%@ page import="oscar.log.LogAction" %>
@@ -80,46 +79,32 @@
}
boolean passwordUpdateRequired = false;
+ String oldPassword = request.getParameter("oldpassword");
+ String newPassword = request.getParameter("mypassword");
+ String confirmPassword = request.getParameter("confirmpassword");
+
//check if the user will change the Password
- if (request.getParameter("oldpassword") != null && request.getParameter("oldpassword").length() > 0 &&
- request.getParameter("mypassword") != null && request.getParameter("mypassword").length() > 0 &&
- request.getParameter("confirmpassword") != null && request.getParameter("confirmpassword").length() > 0) {
-
- StringBuffer sbTemp = new StringBuffer();
- byte[] btOldPasswd= md.digest(request.getParameter("oldpassword").getBytes());
- for(int i=0; i