Add improvements of OTP management

try_it
Lasantha Dharmakeerthi 2 years ago
parent ba42f79fba
commit cfe805ab43

@ -1,49 +0,0 @@
/* Copyright (c) 2023, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. licenses this file to you under the Apache 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://www.apache.org/licenses/LICENSE-2.0
*
* 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.wso2.carbon.device.mgt.common.otp.mgt.wrapper;
public class DownloadURLDetails {
private String firstName;
private String URL;
private String email;
public String getURL() {
return URL;
}
public void setURL(String URL) {
this.URL = URL;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}

@ -22,21 +22,11 @@ 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.invitation.mgt.DeviceEnrollmentInvitation;
import org.wso2.carbon.device.mgt.common.otp.mgt.dto.OneTimePinDTO;
import org.wso2.carbon.device.mgt.common.otp.mgt.wrapper.DownloadURLDetails;
import org.wso2.carbon.device.mgt.common.otp.mgt.wrapper.OTPWrapper;
import java.util.Map;
public interface OTPManagementService {
/**
* Create OTP token and store tenant details in the DB
* @param otpWrapper OTP Mail Wrapper object which contains tenant details of registering user
* @throws OTPManagementException if error occurs while creating OTP token and storing tenant details.
* @throws BadRequestException if found and incompatible payload to create OTP token.
*/
String sendUserVerifyingMail(OTPWrapper otpWrapper) throws OTPManagementException, DeviceManagementException;
/**
* Check the validity of the OTP
* @param oneTimeToken OTP
@ -64,12 +54,11 @@ public interface OTPManagementService {
void sendDeviceEnrollmentInvitationMail(DeviceEnrollmentInvitation deviceEnrollmentInvitation)
throws OTPManagementException;
/**
* Send an e-mail to the requesting e-mail address with a product download URL
* @param downloadURLDetails Contains the details to send product download e-mail
* @throws OTPManagementException if request payload doesn't contains required details to send the product
* download mail.
*/
void shareProductDownloadUrl(DownloadURLDetails downloadURLDetails) throws OTPManagementException;
}
boolean hasEmailRegistered(String email, String emailDomain) throws OTPManagementException,
DeviceManagementException;
OneTimePinDTO generateOneTimePin(String email, String emailType, String userName, Object metaDataObj,
int tenantId, boolean persistPin) throws OTPManagementException;
}

@ -20,7 +20,6 @@ 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.base.MultitenantConstants;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException;
@ -28,42 +27,32 @@ 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.exceptions.UnAuthorizedException;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitation;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentInvitationDetails;
import org.wso2.carbon.device.mgt.common.invitation.mgt.DeviceEnrollmentType;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import org.wso2.carbon.device.mgt.common.otp.mgt.OTPEmailTypes;
import org.wso2.carbon.device.mgt.common.otp.mgt.dto.OneTimePinDTO;
import org.wso2.carbon.device.mgt.common.otp.mgt.wrapper.DownloadURLDetails;
import org.wso2.carbon.device.mgt.common.spi.OTPManagementService;
import org.wso2.carbon.device.mgt.core.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager;
import org.wso2.carbon.device.mgt.core.config.DeviceManagementConfig;
import org.wso2.carbon.device.mgt.core.config.keymanager.KeyManagerConfigurations;
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.OTPWrapper;
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.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.core.service.EmailMetaInfo;
import org.apache.commons.validator.routines.EmailValidator;
import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
import org.wso2.carbon.user.api.Tenant;
import org.wso2.carbon.user.api.UserStoreException;
import static org.wso2.carbon.device.mgt.common.DeviceManagementConstants.OTPProperties;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.ArrayList;
import java.util.Collections;
public class OTPManagementServiceImpl implements OTPManagementService {
@ -79,60 +68,25 @@ public class OTPManagementServiceImpl implements OTPManagementService {
}
@Override
public String sendUserVerifyingMail(OTPWrapper otpWrapper) throws OTPManagementException, DeviceManagementException {
Tenant tenant = validateTenantCreatingDetails(otpWrapper);
OneTimePinDTO oneTimePinDTO = createOneTimePin(otpWrapper.getEmail(), otpWrapper.getEmailType(),
otpWrapper.getUsername(), tenant, -1234);
public boolean hasEmailRegistered(String email, String emailDomain) throws OTPManagementException,
DeviceManagementException {
try {
ConnectionManagerUtil.beginDBTransaction();
this.otpManagementDAO.addOTPData(Collections.singletonList(oneTimePinDTO));
// Properties props = new Properties();
// props.setProperty("first-name", tenant.getAdminFirstName());
// props.setProperty("otp-token", oneTimePinDTO.getOtpToken());
// sendMail(props, tenant.getEmail(), DeviceManagementConstants.EmailAttributes.USER_VERIFY_TEMPLATE);
ConnectionManagerUtil.commitDBTransaction();
return oneTimePinDTO.getOtpToken();
} catch (TransactionManagementException e) {
String msg = "Error occurred while disabling AutoCommit.";
log.error(msg, e);
throw new OTPManagementException(msg, e);
} catch (DBConnectionException e) {
String msg = "Error occurred while getting database connection to add OPT data.";
log.error(msg, e);
throw new OTPManagementException(msg, e);
} catch (OTPManagementDAOException e) {
ConnectionManagerUtil.rollbackDBTransaction();
String msg = "Error occurred while saving the OTP data for given email" ;
log.error(msg, e);
throw new OTPManagementException(msg, e);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
}
@Override
public void shareProductDownloadUrl(DownloadURLDetails downloadURLDetails) throws OTPManagementException {
if (StringUtils.isBlank(downloadURLDetails.getURL())) {
String msg = "Couldn't find the download URL with the request.";
log.error(msg);
throw new OTPManagementException(msg);
ConnectionManagerUtil.openDBConnection();
if (otpManagementDAO.isEmailExist(email, emailDomain)) {
return true;
}
if (StringUtils.isBlank(downloadURLDetails.getFirstName())) {
String msg = "Couldn't find the First Name with the request.";
} catch (DBConnectionException e) {
String msg = "Error occurred while getting database connection to validate the given email and email type.";
log.error(msg);
throw new OTPManagementException(msg);
}
if (StringUtils.isBlank(downloadURLDetails.getEmail())) {
String msg = "Couldn't find the e-mail address with the request.";
throw new DeviceManagementException(msg);
} catch (OTPManagementDAOException e) {
String msg = "Error occurred while executing SQL query to validate the given email and email type.";
log.error(msg);
throw new OTPManagementException(msg);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
Properties props = new Properties();
props.setProperty("first-name", downloadURLDetails.getFirstName());
props.setProperty("download-url", downloadURLDetails.getURL());
sendMail(props, downloadURLDetails.getEmail(),
DeviceManagementConstants.EmailAttributes.PRODUCT_DOWNLOAD_LINK_SHARING_TEMPLATE);
return false;
}
@Override
@ -157,7 +111,7 @@ public class OTPManagementServiceImpl implements OTPManagementService {
Calendar calendar = Calendar.getInstance();
Timestamp currentTimestamp = new Timestamp(calendar.getTime().getTime());
Timestamp expiredTimestamp = new Timestamp(
oneTimePinDTO.getCreatedAt().getTime() + oneTimePinDTO.getExpiryTime() * 1000);
oneTimePinDTO.getCreatedAt().getTime() + oneTimePinDTO.getExpiryTime() * 1000L);
if (currentTimestamp.after(expiredTimestamp)) {
String renewedOTP = UUID.randomUUID().toString();
@ -168,6 +122,8 @@ public class OTPManagementServiceImpl implements OTPManagementService {
Properties props = new Properties();
props.setProperty("first-name", tenant.getAdminFirstName());
props.setProperty("otp-token", renewedOTP);
props.setProperty("email", oneTimePinDTO.getEmail());
props.setProperty("type", oneTimePinDTO.getEmailType());
sendMail(props, oneTimePinDTO.getEmail(), DeviceManagementConstants.EmailAttributes.USER_VERIFY_TEMPLATE);
return null;
}
@ -251,8 +207,8 @@ public class OTPManagementServiceImpl implements OTPManagementService {
for (String username : deviceEnrollmentInvitation.getUsernames()) {
String emailAddress = DeviceManagerUtil.getUserClaimValue(
username, DeviceManagementConstants.User.CLAIM_EMAIL_ADDRESS);
oneTimePinDTO = createOneTimePin(emailAddress, OTPEmailTypes.DEVICE_ENROLLMENT.toString(), username,
null, tenantId);
oneTimePinDTO = generateOneTimePin(emailAddress, OTPEmailTypes.DEVICE_ENROLLMENT.toString(), username,
null, tenantId, false);
oneTimePinDTOList.add(oneTimePinDTO);
props.setProperty("first-name", DeviceManagerUtil.
getUserClaimValue(username, DeviceManagementConstants.User.CLAIM_FIRST_NAME));
@ -284,7 +240,6 @@ public class OTPManagementServiceImpl implements OTPManagementService {
}
}
/**
* Create One Time Token
* @param email email
@ -294,8 +249,9 @@ public class OTPManagementServiceImpl implements OTPManagementService {
* @param tenantId tenant Id
* @return {@link OneTimePinDTO}
*/
private OneTimePinDTO createOneTimePin(String email, String emailType, String userName, Object metaDataObj,
int tenantId) {
@Override
public OneTimePinDTO generateOneTimePin(String email, String emailType, String userName, Object metaDataObj,
int tenantId, boolean persistPin) throws OTPManagementException {
String otpValue = UUID.randomUUID().toString();
@ -310,6 +266,28 @@ public class OTPManagementServiceImpl implements OTPManagementService {
oneTimePinDTO.setMetaInfo(metaInfo);
oneTimePinDTO.setOtpToken(otpValue);
if (persistPin) {
try {
ConnectionManagerUtil.beginDBTransaction();
this.otpManagementDAO.addOTPData(Collections.singletonList(oneTimePinDTO));
ConnectionManagerUtil.commitDBTransaction();
} catch (TransactionManagementException e) {
String msg = "Error occurred while disabling AutoCommit.";
log.error(msg, e);
throw new OTPManagementException(msg, e);
} catch (DBConnectionException e) {
String msg = "Error occurred while getting database connection to add OPT data.";
log.error(msg, e);
throw new OTPManagementException(msg, e);
} catch (OTPManagementDAOException e) {
ConnectionManagerUtil.rollbackDBTransaction();
String msg = "Error occurred while saving the OTP data for given email" ;
log.error(msg, e);
throw new OTPManagementException(msg, e);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
}
return oneTimePinDTO;
}
@ -336,121 +314,6 @@ public class OTPManagementServiceImpl implements OTPManagementService {
}
}
/**
* Validate Tenant details
* @param otpWrapper OTP-Wrapper
* @return {@link Tenant} if its valid payload otherwise throws {@link DeviceManagementException}
* @throws DeviceManagementException if invalid payload or unauthorized request received
*/
private Tenant validateTenantCreatingDetails(OTPWrapper otpWrapper) throws DeviceManagementException {
DeviceManagementConfig deviceManagementConfig = DeviceConfigurationManager.getInstance()
.getDeviceManagementConfig();
KeyManagerConfigurations kmConfig = deviceManagementConfig.getKeyManagerConfigurations();
if (StringUtils.isBlank(otpWrapper.getUsername())) {
String msg = "Received Blank username to create OTP. Username: " + otpWrapper.getUsername();
log.error(msg);
throw new BadRequestException(msg);
}
String[] superTenantDetails = otpWrapper.getUsername().split("@");
if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(superTenantDetails[superTenantDetails.length - 1])
|| !superTenantDetails[0].equals(kmConfig.getAdminUsername())) {
String msg = "You don't have required permission to create OTP";
log.error(msg);
throw new UnAuthorizedException(msg);
}
Tenant tenant = new Tenant();
List<Metadata> properties = otpWrapper.getProperties();
for (Metadata property : properties) {
if (property == null) {
String msg = "Received invalid property to create OTP.";
log.error(msg);
throw new BadRequestException(msg);
}
switch (property.getMetaKey()) {
case OTPProperties.FIRST_NAME:
String firstName = property.getMetaValue();
if (StringUtils.isBlank(firstName)) {
String msg = "Received empty or blank first name field with OTP creating payload.";
log.error(msg);
throw new BadRequestException(msg);
}
tenant.setAdminFirstName(firstName);
break;
case OTPProperties.LAST_NAME:
String lastName = property.getMetaValue();
if (StringUtils.isBlank(lastName)) {
String msg = "Received empty or blank last name field with OTP creating payload.";
log.error(msg);
throw new BadRequestException(msg);
}
tenant.setAdminLastName(lastName);
break;
case OTPProperties.TENANT_ADMIN_PASSWORD:
String pwd = property.getMetaValue();
if (StringUtils.isBlank(pwd)) {
String msg = "Received empty or blank admin password field with OTP creating payload.";
log.error(msg);
throw new BadRequestException(msg);
}
tenant.setAdminPassword(pwd);
break;
default:
String msg = "Received invalid key with OTP properties for creating OTP.";
log.error(msg);
throw new BadRequestException(msg);
}
}
if (StringUtils.isBlank(otpWrapper.getEmail())) {
String msg = "Received empty or blank email field with OTP creating payload.";
log.error(msg);
throw new BadRequestException(msg);
}
EmailValidator validator = EmailValidator.getInstance();
if (!validator.isValid(otpWrapper.getEmail())) {
String msg = "Found invalid email. Hence please verify the email address and re-try. Email: " + otpWrapper
.getEmail();
log.error(msg);
throw new BadRequestException(msg);
}
if (StringUtils.isBlank(otpWrapper.getEmailType())) {
String msg = "Received empty or blank email type field with OTP creating payload.";
log.error(msg);
throw new BadRequestException(msg);
}
try {
ConnectionManagerUtil.openDBConnection();
if (otpManagementDAO.isEmailExist(otpWrapper.getEmail(), otpWrapper.getEmailType())) {
String msg = "Email is registered to execute the same action. Hence can't proceed.";
log.error(msg);
throw new BadRequestException(msg);
}
} catch (DBConnectionException e) {
String msg = "Error occurred while getting database connection to validate the given email and email type.";
log.error(msg);
throw new DeviceManagementException(msg);
} catch (OTPManagementDAOException e) {
String msg = "Error occurred while executing SQL query to validate the given email and email type.";
log.error(msg);
throw new DeviceManagementException(msg);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
String[] tenantUsernameDetails = otpWrapper.getEmail().split("@");
tenant.setAdminName(tenantUsernameDetails[0]);
tenant.setDomain(tenantUsernameDetails[tenantUsernameDetails.length - 1]);
tenant.setEmail(otpWrapper.getEmail());
return tenant;
}
/**
* If OTP expired, resend the user verifying mail with renewed OTP
* @param props Mail body properties

@ -36,8 +36,9 @@
Hi $first-name,
</p>
<p style="font-size: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 5px 0px;">
Congratulations!!! Thank you for registering with Entgra cloud. Please click and log in to the
following link to complete your registration with us. Click <a href="$base-url-https/self-register/sign-up?token=$otp-token">here</a>.
Congratulations!!! Thank you for registering with Entgra. Please click on the
following link to complete your registration with us. Click <a
href="$base-url-https/self-register/sign-up?token=$otp-token&type=$type&email=$email>here</a>.
</p>
<p style="font-length: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 5px 0px;">

Loading…
Cancel
Save