mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Merge branch 'tenant-improve' into 'tenant-improve'
Improvements to token API with tenant Id and username See merge request entgra/carbon-device-mgt!609
This commit is contained in:
commit
1d465c2909
@ -23,7 +23,8 @@ public class OTPMailDTO {
|
|||||||
|
|
||||||
int id;
|
int id;
|
||||||
String otpToken;
|
String otpToken;
|
||||||
String tenantDomain;
|
int tenantId;
|
||||||
|
String username;
|
||||||
String email;
|
String email;
|
||||||
String emailType;
|
String emailType;
|
||||||
String metaInfo;
|
String metaInfo;
|
||||||
@ -32,6 +33,22 @@ public class OTPMailDTO {
|
|||||||
boolean isExpired;
|
boolean isExpired;
|
||||||
boolean isTenantCreated;
|
boolean isTenantCreated;
|
||||||
|
|
||||||
|
public int getTenantId() {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenantId(int tenantId) {
|
||||||
|
this.tenantId = tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -94,10 +111,6 @@ public class OTPMailDTO {
|
|||||||
isExpired = expired;
|
isExpired = expired;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTenantDomain() { return tenantDomain; }
|
|
||||||
|
|
||||||
public void setTenantDomain(String tenantDomain) { this.tenantDomain = tenantDomain; }
|
|
||||||
|
|
||||||
public boolean isTenantCreated() { return isTenantCreated; }
|
public boolean isTenantCreated() { return isTenantCreated; }
|
||||||
|
|
||||||
public void setTenantCreated(boolean tenantCreated) { isTenantCreated = tenantCreated; }
|
public void setTenantCreated(boolean tenantCreated) { isTenantCreated = tenantCreated; }
|
||||||
|
|||||||
@ -20,18 +20,18 @@ public class OTPMailWrapper {
|
|||||||
|
|
||||||
private String firstName;
|
private String firstName;
|
||||||
private String lastName;
|
private String lastName;
|
||||||
private String tenantDomain;
|
|
||||||
private String adminUsername;
|
private String adminUsername;
|
||||||
|
int tenantId;
|
||||||
private String adminPassword;
|
private String adminPassword;
|
||||||
private String email;
|
private String email;
|
||||||
private String emailType;
|
private String emailType;
|
||||||
|
|
||||||
public String getTenantDomain() {
|
public int getTenantId() {
|
||||||
return tenantDomain;
|
return tenantId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTenantDomain(String tenantDomain) {
|
public void setTenantId(int tenantId) {
|
||||||
this.tenantDomain = tenantDomain;
|
this.tenantId = tenantId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAdminUsername() {
|
public String getAdminUsername() {
|
||||||
|
|||||||
@ -19,6 +19,7 @@ package org.wso2.carbon.device.mgt.common.spi;
|
|||||||
|
|
||||||
import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException;
|
import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException;
|
||||||
import org.wso2.carbon.device.mgt.common.exceptions.OTPManagementException;
|
import org.wso2.carbon.device.mgt.common.exceptions.OTPManagementException;
|
||||||
|
import org.wso2.carbon.device.mgt.common.otp.mgt.dto.OTPMailDTO;
|
||||||
import org.wso2.carbon.device.mgt.common.otp.mgt.wrapper.OTPMailWrapper;
|
import org.wso2.carbon.device.mgt.common.otp.mgt.wrapper.OTPMailWrapper;
|
||||||
|
|
||||||
public interface OTPManagementService {
|
public interface OTPManagementService {
|
||||||
@ -35,9 +36,9 @@ public interface OTPManagementService {
|
|||||||
/**
|
/**
|
||||||
* Check the validity of the OTP
|
* Check the validity of the OTP
|
||||||
* @param oneTimeToken OTP
|
* @param oneTimeToken OTP
|
||||||
* @return Ture if OTP is valid one, otherise returns false
|
* @return The OTP data
|
||||||
* @throws OTPManagementException if error occurred whle verifying validity of the OPT
|
* @throws OTPManagementException if error occurred whle verifying validity of the OPT
|
||||||
* @throws BadRequestException if found an null value for OTP
|
* @throws BadRequestException if found an null value for OTP
|
||||||
*/
|
*/
|
||||||
boolean isValidOTP(String oneTimeToken) throws OTPManagementException, BadRequestException;
|
OTPMailDTO isValidOTP(String oneTimeToken) throws OTPManagementException, BadRequestException;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,22 +47,24 @@ public class GenericOTPManagementDAOImpl extends AbstractDAOImpl implements OTPM
|
|||||||
|
|
||||||
String sql = "INSERT INTO DM_OTP_DATA "
|
String sql = "INSERT INTO DM_OTP_DATA "
|
||||||
+ "(OTP_TOKEN, "
|
+ "(OTP_TOKEN, "
|
||||||
+ "TENANT_DOMAIN,"
|
|
||||||
+ "EMAIL, "
|
+ "EMAIL, "
|
||||||
+ "EMAIL_TYPE, "
|
+ "EMAIL_TYPE, "
|
||||||
+ "META_INFO, "
|
+ "META_INFO, "
|
||||||
+ "CREATED_AT) VALUES (?, ?, ?, ?, ?, ?)";
|
+ "CREATED_AT,"
|
||||||
|
+ "TENANT_ID,"
|
||||||
|
+ "USERNAME) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||||
try {
|
try {
|
||||||
Connection conn = this.getDBConnection();
|
Connection conn = this.getDBConnection();
|
||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
Timestamp timestamp = new Timestamp(calendar.getTime().getTime());
|
Timestamp timestamp = new Timestamp(calendar.getTime().getTime());
|
||||||
try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
|
try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
|
||||||
stmt.setString(1, otpMailDTO.getOtpToken());
|
stmt.setString(1, otpMailDTO.getOtpToken());
|
||||||
stmt.setString(2, otpMailDTO.getTenantDomain());
|
stmt.setString(2, otpMailDTO.getEmail());
|
||||||
stmt.setString(3, otpMailDTO.getEmail());
|
stmt.setString(3, otpMailDTO.getEmailType());
|
||||||
stmt.setString(4, otpMailDTO.getEmailType());
|
stmt.setString(4, otpMailDTO.getMetaInfo());
|
||||||
stmt.setString(5, otpMailDTO.getMetaInfo());
|
stmt.setTimestamp(5, timestamp);
|
||||||
stmt.setTimestamp(6, timestamp);
|
stmt.setInt(6, otpMailDTO.getTenantId());
|
||||||
|
stmt.setString(7, otpMailDTO.getUsername());
|
||||||
stmt.executeUpdate();
|
stmt.executeUpdate();
|
||||||
try (ResultSet rs = stmt.getGeneratedKeys()) {
|
try (ResultSet rs = stmt.getGeneratedKeys()) {
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
@ -94,14 +96,15 @@ public class GenericOTPManagementDAOImpl extends AbstractDAOImpl implements OTPM
|
|||||||
String sql = "SELECT "
|
String sql = "SELECT "
|
||||||
+ "ID, "
|
+ "ID, "
|
||||||
+ "OTP_TOKEN, "
|
+ "OTP_TOKEN, "
|
||||||
+ "TENANT_DOMAIN,"
|
|
||||||
+ "EMAIL, "
|
+ "EMAIL, "
|
||||||
+ "EMAIL_TYPE, "
|
+ "EMAIL_TYPE, "
|
||||||
+ "META_INFO, "
|
+ "META_INFO, "
|
||||||
+ "CREATED_AT, "
|
+ "CREATED_AT, "
|
||||||
+ "EXPIRY_TIME, "
|
+ "EXPIRY_TIME, "
|
||||||
+ "IS_EXPIRED, "
|
+ "IS_EXPIRED, "
|
||||||
+ "TENANT_CREATED FROM DM_OTP_DATA "
|
+ "TENANT_CREATED,"
|
||||||
|
+ "TENANT_ID, "
|
||||||
|
+ "USERNAME FROM DM_OTP_DATA "
|
||||||
+ "WHERE OTP_TOKEN = ?";
|
+ "WHERE OTP_TOKEN = ?";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -114,7 +117,6 @@ public class GenericOTPManagementDAOImpl extends AbstractDAOImpl implements OTPM
|
|||||||
OTPMailDTO otpMailDTO = new OTPMailDTO();
|
OTPMailDTO otpMailDTO = new OTPMailDTO();
|
||||||
otpMailDTO.setId(rs.getInt("ID"));
|
otpMailDTO.setId(rs.getInt("ID"));
|
||||||
otpMailDTO.setOtpToken(rs.getString("OTP_TOKEN"));
|
otpMailDTO.setOtpToken(rs.getString("OTP_TOKEN"));
|
||||||
otpMailDTO.setTenantDomain(rs.getString("TENANT_DOMAIN"));
|
|
||||||
otpMailDTO.setEmail(rs.getString("EMAIL"));
|
otpMailDTO.setEmail(rs.getString("EMAIL"));
|
||||||
otpMailDTO.setEmailType(rs.getString("EMAIL_TYPE"));
|
otpMailDTO.setEmailType(rs.getString("EMAIL_TYPE"));
|
||||||
otpMailDTO.setMetaInfo(rs.getString("META_INFO"));
|
otpMailDTO.setMetaInfo(rs.getString("META_INFO"));
|
||||||
@ -122,6 +124,8 @@ public class GenericOTPManagementDAOImpl extends AbstractDAOImpl implements OTPM
|
|||||||
otpMailDTO.setExpiryTime(rs.getInt("EXPIRY_TIME"));
|
otpMailDTO.setExpiryTime(rs.getInt("EXPIRY_TIME"));
|
||||||
otpMailDTO.setExpired(rs.getBoolean("IS_EXPIRED"));
|
otpMailDTO.setExpired(rs.getBoolean("IS_EXPIRED"));
|
||||||
otpMailDTO.setTenantCreated(rs.getBoolean("TENANT_CREATED"));
|
otpMailDTO.setTenantCreated(rs.getBoolean("TENANT_CREATED"));
|
||||||
|
otpMailDTO.setTenantId(rs.getInt("TENANT_ID"));
|
||||||
|
otpMailDTO.setUsername(rs.getString("USERNAME"));
|
||||||
return otpMailDTO;
|
return otpMailDTO;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -70,7 +70,8 @@ public class OTPManagementServiceImpl implements OTPManagementService {
|
|||||||
|
|
||||||
OTPMailDTO otpMailDTO = new OTPMailDTO();
|
OTPMailDTO otpMailDTO = new OTPMailDTO();
|
||||||
otpMailDTO.setEmail(otpMailWrapper.getEmail());
|
otpMailDTO.setEmail(otpMailWrapper.getEmail());
|
||||||
otpMailDTO.setTenantDomain(otpMailWrapper.getTenantDomain());
|
otpMailDTO.setTenantId(otpMailDTO.getTenantId());
|
||||||
|
otpMailDTO.setUsername(otpMailWrapper.getAdminUsername());
|
||||||
otpMailDTO.setEmailType(otpMailWrapper.getEmailType());
|
otpMailDTO.setEmailType(otpMailWrapper.getEmailType());
|
||||||
otpMailDTO.setMetaInfo(metaInfo);
|
otpMailDTO.setMetaInfo(metaInfo);
|
||||||
otpMailDTO.setOtpToken(otpValue);
|
otpMailDTO.setOtpToken(otpValue);
|
||||||
@ -104,7 +105,7 @@ public class OTPManagementServiceImpl implements OTPManagementService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidOTP(String oneTimeToken) throws OTPManagementException, BadRequestException {
|
public OTPMailDTO isValidOTP(String oneTimeToken) throws OTPManagementException, BadRequestException {
|
||||||
OTPMailDTO otpMailDTO = getOTPDataByToken(oneTimeToken);
|
OTPMailDTO otpMailDTO = getOTPDataByToken(oneTimeToken);
|
||||||
if (otpMailDTO == null) {
|
if (otpMailDTO == null) {
|
||||||
String msg = "Couldn't found OTP data for the requesting OTP " + oneTimeToken + " In the system.";
|
String msg = "Couldn't found OTP data for the requesting OTP " + oneTimeToken + " In the system.";
|
||||||
@ -114,11 +115,11 @@ public class OTPManagementServiceImpl implements OTPManagementService {
|
|||||||
|
|
||||||
if (otpMailDTO.isExpired()) {
|
if (otpMailDTO.isExpired()) {
|
||||||
log.warn("Token is expired. OTP: " + oneTimeToken);
|
log.warn("Token is expired. OTP: " + oneTimeToken);
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
if (otpMailDTO.isTenantCreated()) {
|
if (otpMailDTO.isTenantCreated()) {
|
||||||
log.warn("Tenant is already created for the token. OTP: " + oneTimeToken);
|
log.warn("Tenant is already created for the token. OTP: " + oneTimeToken);
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
@ -132,9 +133,9 @@ public class OTPManagementServiceImpl implements OTPManagementService {
|
|||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
OTPMailWrapper otpMailWrapper = gson.fromJson(otpMailDTO.getMetaInfo(), OTPMailWrapper.class);
|
OTPMailWrapper otpMailWrapper = gson.fromJson(otpMailDTO.getMetaInfo(), OTPMailWrapper.class);
|
||||||
resendUserVerifyingMail(otpMailWrapper.getFirstName(), renewedOTP, otpMailDTO.getEmail());
|
resendUserVerifyingMail(otpMailWrapper.getFirstName(), renewedOTP, otpMailDTO.getEmail());
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
return true;
|
return otpMailDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -190,8 +191,8 @@ public class OTPManagementServiceImpl implements OTPManagementService {
|
|||||||
log.error("Received empty or blank email type field with OTP creating payload.");
|
log.error("Received empty or blank email type field with OTP creating payload.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (StringUtils.isBlank(otpMailWrapper.getTenantDomain())) {
|
if (otpMailWrapper.getTenantId() != -1234 && otpMailWrapper.getTenantId() < 1) {
|
||||||
log.error("Received empty or blank tenant domain field with OTP creating payload.");
|
log.error("Invalid tenant Id field with OTP creating payload.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -20,9 +20,11 @@ package org.wso2.carbon.webapp.authenticator.framework.authenticator;
|
|||||||
import org.apache.catalina.connector.Response;
|
import org.apache.catalina.connector.Response;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
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.common.spi.OTPManagementService;
|
||||||
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationInfo;
|
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationInfo;
|
||||||
import org.wso2.carbon.webapp.authenticator.framework.Constants;
|
import org.wso2.carbon.webapp.authenticator.framework.Constants;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.Utils.Utils;
|
||||||
import org.wso2.carbon.webapp.authenticator.framework.internal.AuthenticatorFrameworkDataHolder;
|
import org.wso2.carbon.webapp.authenticator.framework.internal.AuthenticatorFrameworkDataHolder;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@ -47,9 +49,13 @@ public class OneTimeTokenAuthenticator implements WebappAuthenticator {
|
|||||||
try {
|
try {
|
||||||
OTPManagementService otpManagementService = AuthenticatorFrameworkDataHolder.getInstance()
|
OTPManagementService otpManagementService = AuthenticatorFrameworkDataHolder.getInstance()
|
||||||
.getOtpManagementService();
|
.getOtpManagementService();
|
||||||
if (otpManagementService.isValidOTP(request.getHeader(Constants.HTTPHeaders.ONE_TIME_TOKEN_HEADER))) {
|
OTPMailDTO validOTP = otpManagementService.isValidOTP(request.getHeader(Constants.HTTPHeaders
|
||||||
|
.ONE_TIME_TOKEN_HEADER));
|
||||||
|
if (validOTP != null) {
|
||||||
authenticationInfo.setStatus(Status.CONTINUE);
|
authenticationInfo.setStatus(Status.CONTINUE);
|
||||||
authenticationInfo.setTenantId(-1);
|
authenticationInfo.setTenantId(validOTP.getTenantId());
|
||||||
|
authenticationInfo.setTenantDomain(Utils.getTenantDomain(validOTP.getTenantId()));
|
||||||
|
authenticationInfo.setUsername(validOTP.getUsername());
|
||||||
} else {
|
} else {
|
||||||
authenticationInfo.setStatus(Status.FAILURE);
|
authenticationInfo.setStatus(Status.FAILURE);
|
||||||
authenticationInfo.setMessage("Invalid OTP token.");
|
authenticationInfo.setMessage("Invalid OTP token.");
|
||||||
|
|||||||
@ -576,7 +576,8 @@ CREATE TABLE IF NOT EXISTS DM_METADATA (
|
|||||||
CREATE TABLE IF NOT EXISTS DM_OTP_DATA (
|
CREATE TABLE IF NOT EXISTS DM_OTP_DATA (
|
||||||
ID INT AUTO_INCREMENT NOT NULL,
|
ID INT AUTO_INCREMENT NOT NULL,
|
||||||
OTP_TOKEN VARCHAR(100) NOT NULL,
|
OTP_TOKEN VARCHAR(100) NOT NULL,
|
||||||
TENANT_DOMAIN VARCHAR(20) NOT NULL,
|
TENANT_ID INT NOT NULL,
|
||||||
|
USERNAME VARCHAR(500) DEFAULT NOT NULL,
|
||||||
EMAIL VARCHAR(100) NOT NULL,
|
EMAIL VARCHAR(100) NOT NULL,
|
||||||
EMAIL_TYPE VARCHAR(20) NOT NULL,
|
EMAIL_TYPE VARCHAR(20) NOT NULL,
|
||||||
META_INFO VARCHAR(20000) NOT NULL,
|
META_INFO VARCHAR(20000) NOT NULL,
|
||||||
|
|||||||
@ -618,7 +618,8 @@ CREATE TABLE DM_METADATA (
|
|||||||
CREATE TABLE DM_OTP_DATA (
|
CREATE TABLE DM_OTP_DATA (
|
||||||
ID INT IDENTITY NOT NULL,
|
ID INT IDENTITY NOT NULL,
|
||||||
OTP_TOKEN VARCHAR(100) NOT NULL,
|
OTP_TOKEN VARCHAR(100) NOT NULL,
|
||||||
TENANT_DOMAIN VARCHAR(20) NOT NULL,
|
TENANT_ID INTEGER NOT NULL,
|
||||||
|
USERNAME VARCHAR(500) NOT NULL,
|
||||||
EMAIL VARCHAR(100) NOT NULL,
|
EMAIL VARCHAR(100) NOT NULL,
|
||||||
EMAIL_TYPE VARCHAR(20) NOT NULL,
|
EMAIL_TYPE VARCHAR(20) NOT NULL,
|
||||||
META_INFO VARCHAR(20000) NOT NULL,
|
META_INFO VARCHAR(20000) NOT NULL,
|
||||||
|
|||||||
@ -634,7 +634,8 @@ CREATE TABLE IF NOT EXISTS DM_METADATA (
|
|||||||
CREATE TABLE IF NOT EXISTS DM_OTP_DATA (
|
CREATE TABLE IF NOT EXISTS DM_OTP_DATA (
|
||||||
ID INT AUTO_INCREMENT NOT NULL,
|
ID INT AUTO_INCREMENT NOT NULL,
|
||||||
OTP_TOKEN VARCHAR(100) NOT NULL,
|
OTP_TOKEN VARCHAR(100) NOT NULL,
|
||||||
TENANT_DOMAIN VARCHAR(20) NOT NULL,
|
TENANT_ID INT NOT NULL,
|
||||||
|
USERNAME VARCHAR(500) NOT NULL,
|
||||||
EMAIL VARCHAR(100) NOT NULL,
|
EMAIL VARCHAR(100) NOT NULL,
|
||||||
EMAIL_TYPE VARCHAR(20) NOT NULL,
|
EMAIL_TYPE VARCHAR(20) NOT NULL,
|
||||||
META_INFO VARCHAR(20000) NOT NULL,
|
META_INFO VARCHAR(20000) NOT NULL,
|
||||||
|
|||||||
@ -982,7 +982,8 @@ END;
|
|||||||
CREATE TABLE DM_OTP_DATA (
|
CREATE TABLE DM_OTP_DATA (
|
||||||
ID NUMBER(10) NOT NULL,
|
ID NUMBER(10) NOT NULL,
|
||||||
OTP_TOKEN VARCHAR2(100) NOT NULL,
|
OTP_TOKEN VARCHAR2(100) NOT NULL,
|
||||||
TENANT_DOMAIN VARCHAR(20) NOT NULL,
|
TENANT_ID INTEGER NOT NULL,
|
||||||
|
USERNAME VARCHAR(500) NOT NULL,
|
||||||
EMAIL VARCHAR2(100) NOT NULL,
|
EMAIL VARCHAR2(100) NOT NULL,
|
||||||
EMAIL_TYPE VARCHAR2(20) NOT NULL,
|
EMAIL_TYPE VARCHAR2(20) NOT NULL,
|
||||||
META_INFO VARCHAR2(20000) NOT NULL,
|
META_INFO VARCHAR2(20000) NOT NULL,
|
||||||
|
|||||||
@ -623,7 +623,8 @@ CREATE SEQUENCE DM_OTP_DATA_seq;
|
|||||||
CREATE TABLE IF NOT EXISTS DM_OTP_DATA (
|
CREATE TABLE IF NOT EXISTS DM_OTP_DATA (
|
||||||
ID INT DEFAULT NEXTVAL ('DM_OTP_DATA_seq') NOT NULL,
|
ID INT DEFAULT NEXTVAL ('DM_OTP_DATA_seq') NOT NULL,
|
||||||
OTP_TOKEN VARCHAR(100) NOT NULL,
|
OTP_TOKEN VARCHAR(100) NOT NULL,
|
||||||
TENANT_DOMAIN VARCHAR(20) NOT NULL,
|
TENANT_ID INTEGER NOT NULL,
|
||||||
|
USERNAME VARCHAR(500) NOT NULL,
|
||||||
EMAIL VARCHAR(100) NOT NULL,
|
EMAIL VARCHAR(100) NOT NULL,
|
||||||
EMAIL_TYPE VARCHAR(20) NOT NULL,
|
EMAIL_TYPE VARCHAR(20) NOT NULL,
|
||||||
META_INFO VARCHAR(20000) NOT NULL,
|
META_INFO VARCHAR(20000) NOT NULL,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user