Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hash confirmation-code/otp used in recovery #763

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ public enum ErrorMessages {
ERROR_CODE_ERROR_GETTING_CONNECTOR_CONFIG("20062", "Error while getting connector configurations"),
ERROR_CODE_STORING_RECOVERY_FLOW_DATA("20063", "Error while storing recovery data."),
ERROR_CODE_UPDATING_RECOVERY_FLOW_DATA("20064", "Error while updating recovery data."),
ERROR_CODE_NO_HASHING_ALGO_FOR_CODE("20065", "Error while hashing the code."),

ERROR_CODE_ERROR_RETRIVING_CLAIM("18004", "Error when retrieving the locale claim of user '%s' of '%s' domain."),
ERROR_CODE_RECOVERY_DATA_NOT_FOUND_FOR_USER("18005", "Recovery data not found."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@

import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.UUID;

Expand Down Expand Up @@ -169,6 +170,7 @@ public ResendConfirmationDTO resendConfirmation(String tenantDomain, String rese
String notificationChannel = validateNotificationChannel(userRecoveryData.getRemainingSetIds());

String confirmationCode;
String hashedConfirmationCode;
UserRecoveryData confirmationCodeRecoveryData = userRecoveryDataStore.loadWithoutCodeExpiryValidation(user,
scenario, step);
/* Checking whether the existing confirmation code can be used based on the email confirmation code tolerance
Expand All @@ -180,8 +182,14 @@ public ResendConfirmationDTO resendConfirmation(String tenantDomain, String rese
confirmationCode = Utils.generateSecretKey(notificationChannel, user.getTenantDomain(), recoveryScenario);
confirmationCode = Utils.concatRecoveryFlowIdWithSecretKey(recoveryFlowId, notificationChannel,
confirmationCode);
try {
hashedConfirmationCode = Utils.hashCode(confirmationCode);
} catch (NoSuchAlgorithmException e) {
throw Utils.handleServerException(
IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_HASHING_ALGO_FOR_CODE, null);
}
// Store new confirmation code.
addRecoveryDataObject(confirmationCode, recoveryFlowId, notificationChannel, scenario, step, user);
addRecoveryDataObject(hashedConfirmationCode, recoveryFlowId, notificationChannel, scenario, step, user);
}
ResendConfirmationDTO resendConfirmationDTO = new ResendConfirmationDTO();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import org.wso2.carbon.identity.user.functionality.mgt.exception.UserFunctionalityManagementException;
import org.wso2.carbon.identity.user.functionality.mgt.model.FunctionalityLockStatus;

import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Map;
import java.util.UUID;
Expand Down Expand Up @@ -192,8 +193,18 @@ public PasswordResetCodeDTO confirm(String confirmationCode, String tenantDomain
validateTenantDomain(tenantDomain);
UserAccountRecoveryManager userAccountRecoveryManager = UserAccountRecoveryManager.getInstance();
// Get Recovery data.
UserRecoveryData userRecoveryData = userAccountRecoveryManager
.getUserRecoveryData(confirmationCode, RecoverySteps.UPDATE_PASSWORD);
UserRecoveryData userRecoveryData;
try {
String hashedConfirmationCode = Utils.hashCode(confirmationCode);
userRecoveryData = userAccountRecoveryManager
.getUserRecoveryData(hashedConfirmationCode, RecoverySteps.UPDATE_PASSWORD);
} catch (NoSuchAlgorithmException e) {
throw Utils.handleServerException(
IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_HASHING_ALGO_FOR_CODE, null);
} catch (IdentityRecoveryException e) {
userRecoveryData = userAccountRecoveryManager
.getUserRecoveryData(confirmationCode, RecoverySteps.UPDATE_PASSWORD);
}
if (!tenantDomain.equals(userRecoveryData.getUser().getTenantDomain())) {
throw Utils.handleClientException(
IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_USER_TENANT_DOMAIN_MISS_MATCH_WITH_CONTEXT,
Expand Down Expand Up @@ -247,7 +258,15 @@ public PasswordResetCodeDTO confirm(String otp, String confirmationCode, String
}
String domainQualifiedName = IdentityUtil.addDomainToName(userRecoveryData.getUser().getUserName(),
userRecoveryData.getUser().getUserStoreDomain());
if (StringUtils.equals(code, userRecoveryData.getSecret())) {
String hashedCode;
try {
hashedCode = Utils.hashCode(code);
} catch (NoSuchAlgorithmException e) {
throw Utils.handleServerException(
IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_HASHING_ALGO_FOR_CODE, null);
}
if (StringUtils.equals(hashedCode, userRecoveryData.getSecret()) || StringUtils.equals(code,
userRecoveryData.getSecret())) {
if (log.isDebugEnabled()) {
log.debug("Valid confirmation code for user: " + domainQualifiedName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@

import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -251,6 +252,7 @@ private UserRecoveryData generateNewConfirmationCode(User user, String notificat
throws IdentityRecoveryException {

String recoveryFlowId = null;
String hashedSecretKey;
UserRecoveryDataStore userRecoveryDataStore = JDBCRecoveryDataStore.getInstance();
UserRecoveryData userRecoveryData = userRecoveryDataStore.loadWithoutCodeExpiryValidation(user);
if (userRecoveryData != null) {
Expand All @@ -260,12 +262,22 @@ private UserRecoveryData generateNewConfirmationCode(User user, String notificat
String secretKey = Utils.generateSecretKey(notificationChannel, user.getTenantDomain(),
RecoveryScenarios.NOTIFICATION_BASED_PW_RECOVERY.name());
secretKey = Utils.concatRecoveryFlowIdWithSecretKey(recoveryFlowId, notificationChannel, secretKey);
try {
hashedSecretKey = Utils.hashCode(secretKey);
} catch (NoSuchAlgorithmException e) {
throw Utils.handleServerException(
IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_HASHING_ALGO_FOR_CODE, null);
}
UserRecoveryData recoveryDataDO = new UserRecoveryData(user, recoveryFlowId, secretKey,
RecoveryScenarios.NOTIFICATION_BASED_PW_RECOVERY, RecoverySteps.UPDATE_PASSWORD);
UserRecoveryData hashedRecoveryDataDO = new UserRecoveryData(user, recoveryFlowId, hashedSecretKey,
RecoveryScenarios.NOTIFICATION_BASED_PW_RECOVERY, RecoverySteps.UPDATE_PASSWORD);


// Store the notified channel in the recovery object for future reference.
recoveryDataDO.setRemainingSetIds(notificationChannel);
userRecoveryDataStore.storeConfirmationCode(recoveryDataDO);
hashedRecoveryDataDO.setRemainingSetIds(notificationChannel);
userRecoveryDataStore.storeConfirmationCode(hashedRecoveryDataDO);
return recoveryDataDO;
}

Expand Down Expand Up @@ -570,7 +582,16 @@ public User updateUserPassword(String code, String password, Property[] properti


UserRecoveryDataStore userRecoveryDataStore = JDBCRecoveryDataStore.getInstance();
UserRecoveryData userRecoveryData = userRecoveryDataStore.load(code);
UserRecoveryData userRecoveryData;
try {
String hashedCode = Utils.hashCode(code);
userRecoveryData = userRecoveryDataStore.load(hashedCode);
} catch (NoSuchAlgorithmException e) {
throw Utils.handleServerException(
IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_HASHING_ALGO_FOR_CODE, null);
} catch (IdentityRecoveryException e) {
userRecoveryData = userRecoveryDataStore.load(code);
}
validateCallback(properties, userRecoveryData.getUser().getTenantDomain());
publishEvent(userRecoveryData.getUser(), null, code, password, properties,
IdentityEventConstants.Event.PRE_ADD_NEW_PASSWORD, userRecoveryData);
Expand Down Expand Up @@ -670,7 +691,15 @@ public User updateUserPassword(String code, String confirmationCode, String pass
validateTenantDomain(userRecoveryData.getUser());
int failedAttempts = userRecoveryData.getFailedAttempts();

if (!StringUtils.equals(code, userRecoveryData.getSecret())) {
String hashedCode;
try {
hashedCode = Utils.hashCode(code);
} catch (NoSuchAlgorithmException e) {
throw Utils.handleServerException(
IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_HASHING_ALGO_FOR_CODE, null);
}
if (!(StringUtils.equals(hashedCode, userRecoveryData.getSecret()) || StringUtils.equals(code,
userRecoveryData.getSecret()))) {
if ((failedAttempts + 1) >= Integer.parseInt(Utils.getRecoveryConfigs(IdentityRecoveryConstants.
ConnectorConfig.RECOVERY_OTP_PASSWORD_MAX_FAILED_ATTEMPTS, userRecoveryData.getUser().
getTenantDomain()))) {
Expand Down Expand Up @@ -1046,7 +1075,16 @@ public void validateConfirmationCode(String code, String recoveryStep) throws Id
public User getValidatedUser(String code, String recoveryStep) throws IdentityRecoveryException {

UserRecoveryDataStore userRecoveryDataStore = JDBCRecoveryDataStore.getInstance();
UserRecoveryData userRecoveryData = userRecoveryDataStore.load(code);
UserRecoveryData userRecoveryData;
try {
String hashedCode = Utils.hashCode(code);
userRecoveryData = userRecoveryDataStore.load(hashedCode);
} catch (NoSuchAlgorithmException e) {
throw Utils.handleServerException(
IdentityRecoveryConstants.ErrorMessages.ERROR_CODE_NO_HASHING_ALGO_FOR_CODE, null);
} catch (IdentityRecoveryException e) {
userRecoveryData = userRecoveryDataStore.load(code);
}
String contextTenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
String userTenantDomain = userRecoveryData.getUser().getTenantDomain();
if (!StringUtils.equals(contextTenantDomain, userTenantDomain)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,19 @@ public static String doHash(String value) throws UserStoreException {
}
}

/**
* @param value Value to be hashed
* @return Hashed value
* @throws NoSuchAlgorithmException If the algorithm is not found.
*/
public static String hashCode(String value) throws NoSuchAlgorithmException {
Rashmini marked this conversation as resolved.
Show resolved Hide resolved

String digsestFunction = "SHA-256";
MessageDigest dgst = MessageDigest.getInstance(digsestFunction);
byte[] byteValue = dgst.digest(value.getBytes(StandardCharsets.UTF_8));
return Base64.encode(byteValue);
}

/**
* Set claim to user store manager
*
Expand Down
Loading