From 3d2f474e75b5fb539fba4206b7508eaf9f05953b Mon Sep 17 00:00:00 2001 From: Dharmakeerthi Lasantha Date: Thu, 30 Jul 2020 12:54:35 +0000 Subject: [PATCH] Improve OTP creating functionality --- .../mgt/common/spi/OTPManagementService.java | 9 ++- .../core/otp/mgt/dao/OTPManagementDAO.java | 16 +++- .../dao/impl/GenericOTPManagementDAOImpl.java | 61 ++++++++++++++- .../mgt/service/OTPManagementServiceImpl.java | 74 ++++++++++++++++++- .../OneTimeTokenAuthenticator.java | 25 +++---- 5 files changed, 163 insertions(+), 22 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/spi/OTPManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/spi/OTPManagementService.java index 24ec41d229..6ce92c27c9 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/spi/OTPManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/spi/OTPManagementService.java @@ -24,7 +24,7 @@ import org.wso2.carbon.device.mgt.common.otp.mgt.wrapper.OTPMailWrapper; public interface OTPManagementService { /** - * Cretae OTP token and store tenant details in the DB + * Create OTP token and store tenant details in the DB * @param otpMailWrapper OTP Mail Wrapper object which contains tenant details of registering user * @return OTPToken * @throws OTPManagementException if error occurs while creating OTP token and storing tenant details. @@ -32,5 +32,12 @@ public interface OTPManagementService { */ String createOTPToken (OTPMailWrapper otpMailWrapper) throws OTPManagementException, BadRequestException; + /** + * Check the validity of the OTP + * @param oneTimeToken OTP + * @return Ture if OTP is valid one, otherise returns false + * @throws OTPManagementException if error occurred whle verifying validity of the OPT + * @throws BadRequestException if found an null value for OTP + */ boolean isValidOTP(String oneTimeToken) throws OTPManagementException, BadRequestException; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/dao/OTPManagementDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/dao/OTPManagementDAO.java index 64288ced22..9a9ae3eefb 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/dao/OTPManagementDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/dao/OTPManagementDAO.java @@ -38,5 +38,19 @@ public interface OTPManagementDAO { */ OTPMailDTO getOTPDataByToken (String oneTimeToken) throws OTPManagementDAOException; - void ExpireOneTimeToken (String oneTimeToken); + /** + * Expire the OTP + * @param oneTimeToken OTP + * @throws OTPManagementDAOException if error occurred while updating the OTP validity. + */ + void expireOneTimeToken(String oneTimeToken) throws OTPManagementDAOException; + + /** + * Update OTP with renewed OTP + * @param id ID + * @param oneTimeToken One Time Token + * @throws OTPManagementDAOException if error occured while updating OTP + */ + void renewOneTimeToken(int id, String oneTimeToken) throws OTPManagementDAOException; + } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/dao/impl/GenericOTPManagementDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/dao/impl/GenericOTPManagementDAOImpl.java index b8ec791faf..7cc27618a1 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/dao/impl/GenericOTPManagementDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/dao/impl/GenericOTPManagementDAOImpl.java @@ -140,7 +140,66 @@ public class GenericOTPManagementDAOImpl extends AbstractDAOImpl implements OTPM } @Override - public void ExpireOneTimeToken (String oneTimeToken) { + public void expireOneTimeToken(String oneTimeToken) throws OTPManagementDAOException { + if (log.isDebugEnabled()) { + log.debug("Request received in DAO Layer to update an OTP data entry for OTP"); + log.debug("OTP Details : OTP key : " + oneTimeToken ); + } + + String sql = "UPDATE DM_OTP_DATA " + + "SET " + + "IS_EXPIRED = ? " + + "WHERE OTP_TOKEN = ?"; + + try { + Connection conn = this.getDBConnection(); + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setBoolean(1, true); + stmt.setString(2, oneTimeToken); + stmt.executeUpdate(); + } + } catch (DBConnectionException e) { + String msg = "Error occurred while obtaining the DB connection to update the OTP token validity."; + log.error(msg, e); + throw new OTPManagementDAOException(msg, e); + } catch (SQLException e) { + String msg = "Error occurred when obtaining database connection for updating the OTP token validity."; + log.error(msg, e); + throw new OTPManagementDAOException(msg, e); + } + } + + @Override + public void renewOneTimeToken(int id, String oneTimeToken) throws OTPManagementDAOException { + if (log.isDebugEnabled()) { + log.debug("Request received in DAO Layer to update an OTP data entry for OTP"); + log.debug("OTP Details : OTP key : " + oneTimeToken ); + } + + String sql = "UPDATE DM_OTP_DATA " + + "SET " + + "OTP_TOKEN = ? " + + "CREATED_AT = ? " + + "WHERE ID = ?"; + try { + Connection conn = this.getDBConnection(); + Calendar calendar = Calendar.getInstance(); + Timestamp timestamp = new Timestamp(calendar.getTime().getTime()); + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, oneTimeToken); + stmt.setTimestamp(2, timestamp); + stmt.setInt(3, id); + stmt.executeUpdate(); + } + } catch (DBConnectionException e) { + String msg = "Error occurred while obtaining the DB connection to update the OTP token validity."; + log.error(msg, e); + throw new OTPManagementDAOException(msg, e); + } catch (SQLException e) { + String msg = "Error occurred when obtaining database connection for updating the OTP token validity."; + log.error(msg, e); + throw new OTPManagementDAOException(msg, e); + } } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/service/OTPManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/service/OTPManagementServiceImpl.java index 464c2da922..47ef466114 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/service/OTPManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/otp/mgt/service/OTPManagementServiceImpl.java @@ -20,21 +20,26 @@ import com.google.gson.Gson; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException; import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException; import org.wso2.carbon.device.mgt.common.exceptions.DBConnectionException; +import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.OTPManagementException; import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException; import org.wso2.carbon.device.mgt.common.otp.mgt.dto.OTPMailDTO; import org.wso2.carbon.device.mgt.common.spi.OTPManagementService; +import org.wso2.carbon.device.mgt.core.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder; import org.wso2.carbon.device.mgt.core.otp.mgt.dao.OTPManagementDAO; import org.wso2.carbon.device.mgt.common.otp.mgt.wrapper.OTPMailWrapper; import org.wso2.carbon.device.mgt.core.otp.mgt.dao.OTPManagementDAOFactory; import org.wso2.carbon.device.mgt.core.otp.mgt.exception.OTPManagementDAOException; import org.wso2.carbon.device.mgt.core.otp.mgt.util.ConnectionManagerUtil; +import org.wso2.carbon.device.mgt.core.service.EmailMetaInfo; -import java.sql.Time; import java.sql.Timestamp; import java.util.Calendar; +import java.util.Properties; import java.util.UUID; public class OTPManagementServiceImpl implements OTPManagementService { @@ -108,6 +113,11 @@ public class OTPManagementServiceImpl implements OTPManagementService { } if (otpMailDTO.isExpired()) { + log.warn("Token is expired. OTP: " + oneTimeToken); + return false; + } + if (otpMailDTO.isTenantCreated()) { + log.warn("Tenant is already created for the token. OTP: " + oneTimeToken); return false; } @@ -117,12 +127,14 @@ public class OTPManagementServiceImpl implements OTPManagementService { otpMailDTO.getCreatedAt().getTime() + otpMailDTO.getExpiryTime() * 1000); if (currentTimestamp.after(expiredTimestamp)) { - //todo update the DB + String renewedOTP = UUID.randomUUID().toString(); + renewOTP(otpMailDTO, renewedOTP); + Gson gson = new Gson(); + OTPMailWrapper otpMailWrapper = gson.fromJson(otpMailDTO.getMetaInfo(), OTPMailWrapper.class); + resendUserVerifyingMail(otpMailWrapper.getFirstName(), renewedOTP, otpMailDTO.getEmail()); return false; } - return true; - } /** @@ -184,4 +196,58 @@ public class OTPManagementServiceImpl implements OTPManagementService { } return true; } + + /** + * If OTP expired, resend the user verifying mail with renewed OTP + * @param firstName First Name of the User + * @param renewedOTP Renewed OTP + * @param mailAddress Mail Address of the User + * @throws OTPManagementException if error occurred while resend the user verifying mail + */ + private void resendUserVerifyingMail(String firstName, String renewedOTP, String mailAddress) + throws OTPManagementException { + Properties props = new Properties(); + props.setProperty("first-name", firstName); + props.setProperty("otp-token", renewedOTP); + + EmailMetaInfo metaInfo = new EmailMetaInfo(mailAddress, props); + try { + DeviceManagementDataHolder.getInstance().getDeviceManagementProvider() + .sendEnrolmentInvitation(DeviceManagementConstants.EmailAttributes.USER_VERIFY_TEMPLATE, metaInfo); + } catch (DeviceManagementException e) { + e.printStackTrace(); + throw new OTPManagementException(e); + } catch (ConfigurationManagementException e) { + throw new OTPManagementException(e); + } + } + + /** + * Renew the OTP + * @param otpMailDTO {@link OTPMailDTO} + * @param renewedOTP Renewed OTP + * @throws OTPManagementException if error occurred while renew the OTP + */ + private void renewOTP(OTPMailDTO otpMailDTO, String renewedOTP) throws OTPManagementException { + try { + ConnectionManagerUtil.beginDBTransaction(); + this.otpManagementDAO.renewOneTimeToken(otpMailDTO.getId(), renewedOTP); + ConnectionManagerUtil.commitDBTransaction(); + } catch (TransactionManagementException e) { + String msg = "Error occurred while disabling AutoCommit to renew the OTP."; + log.error(msg, e); + throw new OTPManagementException(msg, e); + } catch (DBConnectionException e) { + String msg = "Error occurred while getting database connection to renew the OTP."; + log.error(msg, e); + throw new OTPManagementException(msg, e); + } catch (OTPManagementDAOException e) { + ConnectionManagerUtil.rollbackDBTransaction(); + String msg = "Error occurred while renew the OTP. OTP: " + renewedOTP; + log.error(msg, e); + throw new OTPManagementException(msg, e); + } finally { + ConnectionManagerUtil.closeDBConnection(); + } + } } diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/OneTimeTokenAuthenticator.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/OneTimeTokenAuthenticator.java index 636b0052a4..d150f6ee3f 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/OneTimeTokenAuthenticator.java +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/OneTimeTokenAuthenticator.java @@ -20,7 +20,6 @@ package org.wso2.carbon.webapp.authenticator.framework.authenticator; import org.apache.catalina.connector.Response; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.device.mgt.common.general.OneTimeTokenDetails; import org.wso2.carbon.device.mgt.common.spi.OTPManagementService; import org.wso2.carbon.webapp.authenticator.framework.AuthenticationInfo; import org.wso2.carbon.webapp.authenticator.framework.Constants; @@ -45,25 +44,21 @@ public class OneTimeTokenAuthenticator implements WebappAuthenticator { OTPManagementService otpManagementService = AuthenticatorFrameworkDataHolder.getInstance() .getOtpManagementService(); - - - String token = request.getHeader(Constants.HTTPHeaders.ONE_TIME_TOKEN_HEADER); -// DeviceMgtAPIUtils.getDeviceManagementService();//TODO: call token validate service in core - OneTimeTokenDetails tokenDetails = new OneTimeTokenDetails();//TODO: use token details - AuthenticationInfo authenticationInfo = new AuthenticationInfo(); try { - authenticationInfo.setTenantDomain(tokenDetails.getDomain()); - authenticationInfo.setStatus(Status.CONTINUE); - //authenticationInfo.setUsername(tokenDetails.get); //TODO: set username - //authenticationInfo.setTenantId();//TODO: set tenant Id - } catch (Exception e) { // TODO: remove this if not needed + if (otpManagementService.isValidOTP(request.getHeader(Constants.HTTPHeaders.ONE_TIME_TOKEN_HEADER))) { + authenticationInfo.setStatus(Status.CONTINUE); + authenticationInfo.setTenantId(-1); + } else { + authenticationInfo.setStatus(Status.FAILURE); + authenticationInfo.setMessage("Invalid OTP token."); + } + } catch (Exception e) { authenticationInfo.setStatus(Status.FAILURE); - authenticationInfo.setMessage("Could not identify tenant domain."); + authenticationInfo.setMessage("CToken Validation Failed."); } - - return null; + return authenticationInfo; } public String getName() {