Resolve conflicts

location-fix
osh 1 year ago
commit 2249520132

@ -22,11 +22,11 @@ import com.google.gson.JsonObject;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.GrafanaAPIProxyService;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.bean.ErrorResponse;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.exception.RefererNotValid;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.impl.util.GrafanaMgtAPIUtils;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.impl.util.GrafanaRequestHandlerUtil;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.common.exception.GrafanaManagementException;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.bean.GrafanaPanelIdentifier;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.exception.MaliciousQueryAttempt;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.internal.GrafanaMgtDataHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.DBConnectionException;
@ -57,8 +57,8 @@ public class GrafanaAPIProxyServiceImpl implements GrafanaAPIProxyService {
public Response queryDatasource(JsonObject body, @Context HttpHeaders headers, @Context UriInfo requestUriInfo) {
try {
GrafanaPanelIdentifier panelIdentifier = GrafanaRequestHandlerUtil.getPanelIdentifier(headers);
GrafanaMgtDataHolder.getInstance().getGrafanaQueryService().
buildSafeQuery(body, panelIdentifier.getDashboardId(), panelIdentifier.getPanelId(), requestUriInfo.getRequestUri());
GrafanaMgtAPIUtils.getGrafanaQueryService().buildSafeQuery(body, panelIdentifier.getDashboardId(),
panelIdentifier.getPanelId(), requestUriInfo.getRequestUri());
return GrafanaRequestHandlerUtil.proxyPassPostRequest(body, requestUriInfo, panelIdentifier.getOrgId());
} catch (MaliciousQueryAttempt e) {
return Response.status(Response.Status.BAD_REQUEST).entity(

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018 - 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 io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.impl.util;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.service.GrafanaQueryService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
public class GrafanaMgtAPIUtils {
private static final Log log = LogFactory.getLog(GrafanaMgtAPIUtils.class);
private static volatile GrafanaQueryService grafanaQueryService;
/**
* Accessing GrafanaQueryService from OSGI service context
* @return GrafanaQueryService instance
*/
public static GrafanaQueryService getGrafanaQueryService() {
if (grafanaQueryService == null) {
synchronized (GrafanaMgtAPIUtils.class) {
if (grafanaQueryService == null) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
grafanaQueryService =
(GrafanaQueryService) ctx.getOSGiService(GrafanaQueryService.class, null);
if (grafanaQueryService == null) {
String msg = "Grafana Query service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
}
}
}
return grafanaQueryService;
}
}

@ -88,7 +88,7 @@
io.entgra.device.mgt.core.application.mgt.core.*
</Import-Package>
<Export-Package>
!io.entgra.device.mgt.core.transport.mgt.email.sender.core.internal,
!io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.internal,
io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.*
</Export-Package>
<Embed-Dependency>

@ -26,7 +26,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
/**
* @scr.component name="io.entgra.analytics.mgt.grafana.proxy.grafanamanagementservicecomponent" immediate="true"

@ -62,17 +62,18 @@ public class APIApplicationManagerExtensionDataHolder {
public void setRealmService(RealmService realmService) {
this.realmService = realmService;
this.setTenantManager(realmService);
setTenantManager(realmService != null ?
realmService.getTenantManager() : null);
}
private void setTenantManager(RealmService realmService) {
if (realmService == null) {
throw new IllegalStateException("Realm service is not initialized properly");
}
this.tenantManager = realmService.getTenantManager();
private void setTenantManager(TenantManager tenantManager) {
this.tenantManager = tenantManager;
}
public TenantManager getTenantManager() {
if (tenantManager == null) {
throw new IllegalStateException("Tenant manager is not initialized properly");
}
return tenantManager;
}

@ -75,17 +75,18 @@ public class APIPublisherDataHolder {
public void setRealmService(RealmService realmService) {
this.realmService = realmService;
this.setTenantManager(realmService);
setTenantManager(realmService != null ?
realmService.getTenantManager() : null);
}
private void setTenantManager(RealmService realmService) {
if (realmService == null) {
throw new IllegalStateException("Realm service is not initialized properly");
}
this.tenantManager = realmService.getTenantManager();
private void setTenantManager(TenantManager tenantManager) {
this.tenantManager = tenantManager;
}
public TenantManager getTenantManager() {
if (tenantManager == null) {
throw new IllegalStateException("Tenant manager is not initialized properly");
}
return tenantManager;
}

@ -27,6 +27,7 @@ import io.entgra.device.mgt.core.application.mgt.common.response.Category;
import io.entgra.device.mgt.core.application.mgt.common.response.Tag;
import io.entgra.device.mgt.core.device.mgt.common.Base64File;
import io.entgra.device.mgt.core.application.mgt.common.dto.ApplicationDTO;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.MetadataManagementException;
import org.apache.cxf.jaxrs.ext.multipart.Attachment;
import io.entgra.device.mgt.core.application.mgt.common.ApplicationArtifact;
import io.entgra.device.mgt.core.application.mgt.common.LifecycleChanger;

@ -22,6 +22,8 @@ import io.entgra.device.mgt.core.application.mgt.core.exception.BadRequestExcept
import io.entgra.device.mgt.core.device.mgt.common.Base64File;
import io.entgra.device.mgt.core.application.mgt.core.dao.SPApplicationDAO;
import io.entgra.device.mgt.core.application.mgt.core.util.ApplicationManagementUtil;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.MetadataManagementException;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.Metadata;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
@ -30,6 +32,7 @@ import org.apache.commons.validator.routines.UrlValidator;
import org.apache.cxf.jaxrs.ext.multipart.Attachment;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONObject;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import io.entgra.device.mgt.core.application.mgt.common.ApplicationArtifact;
@ -95,6 +98,7 @@ import io.entgra.device.mgt.core.device.mgt.core.service.DeviceManagementProvide
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import javax.ws.rs.core.Response;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@ -1283,13 +1287,13 @@ public class ApplicationManagerImpl implements ApplicationManager {
this.changeLifecycleState(applicationReleaseDTO, lifecycleChanger);
}
}
if (applicationDTO.getType().equals("ENTERPRISE") || applicationDTO.getType().equals("PUBLIC") ) {
persistAppIconInfo(applicationReleaseDTO);
}
applicationReleaseEntities.add(applicationReleaseDTO);
}
applicationDTO.setId(appId);
applicationDTO.setApplicationReleaseDTOs(applicationReleaseEntities);
if (applicationDTO.getType().equals("ENTERPRISE") || applicationDTO.getType().equals("PUBLIC") ) {
persistAppIconInfo(applicationReleaseDTO);
}
return APIUtil.appDtoToAppResponse(applicationDTO);
}
} catch (LifeCycleManagementDAOException e) {
@ -1713,6 +1717,31 @@ public class ApplicationManagerImpl implements ApplicationManager {
}
}
/**
* Check whether valid metaData value or not
*
* @return true or false
* @throws MetadataManagementException If it is unable to load metaData
*/
private boolean isUserAbleToViewAllRoles() throws MetadataManagementException {
List<Metadata> allMetadata;
allMetadata = APIUtil.getMetadataManagementService().retrieveAllMetadata();
if (allMetadata != null && !allMetadata.isEmpty()) {
for(Metadata metadata : allMetadata){
if(Constants.SHOW_ALL_ROLES.equals(metadata.getMetaKey())){
String metaValue = metadata.getMetaValue();
if (metaValue != null) {
JSONObject jsonObject;
jsonObject = new JSONObject(metaValue);
boolean isUserAbleToViewAllRoles = jsonObject.getBoolean(Constants.IS_USER_ABLE_TO_VIEW_ALL_ROLES);
return isUserAbleToViewAllRoles;
}
}
}
}
return false;
}
/**
* Get assigned role list of the given user.
*
@ -3486,7 +3515,8 @@ public class ApplicationManagerImpl implements ApplicationManager {
}
@Override
public <T> void validateAppCreatingRequest(T param) throws ApplicationManagementException, RequestValidatingException {
public <T> void validateAppCreatingRequest(T param)
throws ApplicationManagementException, RequestValidatingException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
int deviceTypeId = -1;
@ -3658,12 +3688,14 @@ public class ApplicationManagerImpl implements ApplicationManager {
log.error(msg);
throw new ApplicationManagementException(msg);
}
if (!hasUserRole(unrestrictedRoles, userName)) {
String msg = "You are trying to restrict the visibility of the application for a role set, but "
+ "in order to perform the action at least one role should be assigned to user: "
+ userName;
log.error(msg);
throw new BadRequestException(msg);
if (!isUserAbleToViewAllRoles()) {
if (!hasUserRole(unrestrictedRoles, userName)) {
String msg = "You are trying to restrict the visibility of the application for a role set, but "
+ "in order to perform the action at least one role should be assigned to user: "
+ userName;
log.error(msg);
throw new BadRequestException(msg);
}
}
}
@ -3716,6 +3748,10 @@ public class ApplicationManagerImpl implements ApplicationManager {
String msg = "Error occurred when validating the unrestricted roles given for the web clip";
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} catch (MetadataManagementException e) {
String msg = "Error occurred while retrieving metadata list";
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} finally {
ConnectionManagerUtil.closeDBConnection();
}

@ -569,7 +569,22 @@ public class APIUtil {
public static String createAppIconPath(ApplicationReleaseDTO applicationReleaseDTO, int tenantId) throws ApplicationManagementException {
String basePath = getArtifactDownloadBaseURL() + tenantId + Constants.FORWARD_SLASH + applicationReleaseDTO
.getAppHashValue() + Constants.FORWARD_SLASH;
String iconPath = basePath + Constants.ICON_ARTIFACT + Constants.FORWARD_SLASH + applicationReleaseDTO.getIconName();
return iconPath;
return basePath + Constants.ICON_ARTIFACT + Constants.FORWARD_SLASH + applicationReleaseDTO.getIconName();
}
public static MetadataManagementService getMetadataManagementService() {
if (metadataManagementService == null) {
synchronized (APIUtil.class) {
if (metadataManagementService == null) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
metadataManagementService = (MetadataManagementService) ctx.getOSGiService(
MetadataManagementService.class, null);
if (metadataManagementService == null) {
throw new IllegalStateException("Metadata Management service not initialized.");
}
}
}
}
return metadataManagementService;
}
}

@ -70,7 +70,8 @@ public class Constants {
public static final String ANY = "ANY";
public static final String DEFAULT_PCK_NAME = "default.app.com";
public static final String ALL = "ALL";
public static final String SHOW_ALL_ROLES = "SHOW_ALL_ROLES";
public static final String IS_USER_ABLE_TO_VIEW_ALL_ROLES = "isUserAbleToViewAllRoles";
public static final String GOOGLE_PLAY_STORE_URL = "https://play.google.com/store/apps/details?id=";
public static final String APPLE_STORE_URL = "https://itunes.apple.com/country/app/app-name/id";
public static final String GOOGLE_PLAY_SYNCED_APP = "GooglePlaySyncedApp";

@ -25,6 +25,15 @@ public class Certificate {
X509Certificate certificate;
int tenantId;
String tenantDomain;
String deviceIdentifier;
public String getDeviceIdentifier() {
return deviceIdentifier;
}
public void setDeviceIdentifier(String deviceIdentifier) {
this.deviceIdentifier = deviceIdentifier;
}
public int getTenantId() {
return tenantId;

@ -41,6 +41,17 @@ public interface CertificateDAO {
void addCertificate(List<Certificate> certificate)
throws CertificateManagementDAOException;
/**
* This can be used to store a certificate in the database, where it will be stored against the serial number
* of the certificate.
*
* @param certificate Holds the certificate and relevant details.
* @throws CertificateManagementDAOException
*
*/
void addCertificate(Certificate certificate)
throws CertificateManagementDAOException;
/**
* Usage is to obtain a certificate stored in the database by providing the common name.
*
@ -51,6 +62,16 @@ public interface CertificateDAO {
*/
CertificateResponse retrieveCertificate(String serialNumber) throws CertificateManagementDAOException;
/**
* Obtain a certificated stored in the database by providing the common name and the tenant ID
*
* @param serialNumber Serial number (Common name) of the certificate
* @param tenantId ID of the certificate owning tenant
* @return representation of the certificate.
* @throws CertificateManagementDAOException if fails to read the certificate from the database
*/
CertificateResponse retrieveCertificate(String serialNumber, int tenantId) throws CertificateManagementDAOException;
/**
* Get all the certificates in a paginated manner.
*

@ -81,6 +81,40 @@ public abstract class AbstractCertificateDAOImpl implements CertificateDAO{
}
}
@Override
public void addCertificate(Certificate certificate)
throws CertificateManagementDAOException {
Connection conn;
PreparedStatement stmt = null;
try {
conn = this.getConnection();
stmt = conn.prepareStatement(
"INSERT INTO DM_DEVICE_CERTIFICATE (SERIAL_NUMBER, CERTIFICATE, TENANT_ID," +
" USERNAME, DEVICE_IDENTIFIER) VALUES (?,?,?,?,?)");
PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.
getThreadLocalCarbonContext();
String username = threadLocalCarbonContext.getUsername();
// the serial number of the certificate used for its creation is set as its alias.
String serialNumber = certificate.getSerial();
if (serialNumber == null || serialNumber.isEmpty()) {
serialNumber = String.valueOf(certificate.getCertificate().getSerialNumber());
}
byte[] bytes = Serializer.serialize(certificate.getCertificate());
stmt.setString(1, serialNumber);
stmt.setBytes(2, bytes);
stmt.setInt(3, certificate.getTenantId());
stmt.setString(4, username);
stmt.setString(5, certificate.getDeviceIdentifier());
stmt.executeUpdate();
} catch (SQLException | IOException e) {
throw new CertificateManagementDAOException("Error occurred while saving the " +
"certificate. ", e);
} finally {
CertificateManagementDAOUtil.cleanupResources(stmt, null);
}
}
@Override
public CertificateResponse retrieveCertificate(String serialNumber)
throws CertificateManagementDAOException {
@ -119,6 +153,42 @@ public abstract class AbstractCertificateDAOImpl implements CertificateDAO{
return certificateResponse;
}
@Override
public CertificateResponse retrieveCertificate(String serialNumber, int tenantId) throws CertificateManagementDAOException {
Connection conn;
PreparedStatement stmt = null;
ResultSet resultSet = null;
CertificateResponse certificateResponse = null;
try {
conn = this.getConnection();
String query =
"SELECT CERTIFICATE, SERIAL_NUMBER, TENANT_ID, USERNAME FROM"
+ " DM_DEVICE_CERTIFICATE WHERE SERIAL_NUMBER = ? AND TENANT_ID = ? ";
stmt = conn.prepareStatement(query);
stmt.setString(1, serialNumber);
stmt.setInt(2, tenantId);
resultSet = stmt.executeQuery();
if (resultSet.next()) {
certificateResponse = new CertificateResponse();
byte[] certificateBytes = resultSet.getBytes("CERTIFICATE");
certificateResponse.setCertificate(certificateBytes);
certificateResponse.setSerialNumber(resultSet.getString("SERIAL_NUMBER"));
certificateResponse.setTenantId(resultSet.getInt("TENANT_ID"));
certificateResponse.setUsername(resultSet.getString("USERNAME"));
CertificateGenerator.extractCertificateDetails(certificateBytes, certificateResponse);
}
} catch (SQLException e) {
String errorMsg =
"Unable to get the read the certificate with serial" + serialNumber;
log.error(errorMsg, e);
throw new CertificateManagementDAOException(errorMsg, e);
} finally {
CertificateManagementDAOUtil.cleanupResources(stmt, resultSet);
}
return certificateResponse;
}
@Override
public List<CertificateResponse> searchCertificate(String serialNumber)
throws CertificateManagementDAOException {

@ -358,15 +358,31 @@ public class CertificateGenerator {
CertificateResponse lookUpCertificate = null;
KeyStoreReader keyStoreReader = new KeyStoreReader();
if (distinguishedName != null && !distinguishedName.isEmpty()) {
if (distinguishedName.contains("/CN=")) {
String[] dnSplits = distinguishedName.split("/");
for (String dnPart : dnSplits) {
if (dnPart.contains("CN=")) {
String commonNameExtracted = dnPart.replace("CN=", "");
lookUpCertificate = keyStoreReader.getCertificateBySerial(commonNameExtracted);
break;
if (distinguishedName.contains("CN=")) {
String[] dnSplits = null;
if (distinguishedName.contains("/")) {
dnSplits = distinguishedName.split("/");
} else if (distinguishedName.contains(",")) {
//some older versions of nginx will forward the client certificate subject dn separated with commas
dnSplits = distinguishedName.split(",");
}
String commonNameExtracted = null;
int tenantId = 0;
if (dnSplits != null && dnSplits.length >= 1) {
for (String dnPart : dnSplits) {
if (dnPart.contains("CN=")) {
commonNameExtracted = dnPart.replace("CN=", "");
} else if (dnPart.contains("OU=")) {
//the OU of the certificate will be like OU=tenant_<TENANT_ID> ex: OU=tenant_-1234
//splitting by underscore to extract the tenant domain
String[] orgUnitSplits = dnPart.split("_");
tenantId = Integer.parseInt(orgUnitSplits[1]);
}
}
}
lookUpCertificate = keyStoreReader.getCertificateBySerial(commonNameExtracted, tenantId);
} else {
LdapName ldapName;
try {
@ -694,6 +710,30 @@ public class CertificateGenerator {
}
}
public void saveCertificate(io.entgra.device.mgt.core.certificate.mgt.core.bean.Certificate
certificate) throws KeystoreException {
if (certificate == null) {
return;
}
try {
CertificateDAO certificateDAO = CertificateManagementDAOFactory.getCertificateDAO();
CertificateManagementDAOFactory.beginTransaction();
certificateDAO.addCertificate(certificate);
CertificateManagementDAOFactory.commitTransaction();
} catch (CertificateManagementDAOException e) {
String errorMsg = "Error occurred when saving the generated certificate in database";
log.error(errorMsg);
CertificateManagementDAOFactory.rollbackTransaction();
throw new KeystoreException(errorMsg, e);
} catch (TransactionManagementException e) {
String errorMsg = "Error occurred when saving the generated certificate in database";
log.error(errorMsg);
throw new KeystoreException(errorMsg, e);
}
}
public void saveCertInKeyStore(List<io.entgra.device.mgt.core.certificate.mgt.core.bean.Certificate> certificate)
throws KeystoreException {

@ -275,6 +275,43 @@ public class KeyStoreReader {
return raPrivateKey;
}
public CertificateResponse getCertificateBySerial(String serialNumber, int tenantId) throws KeystoreException {
CertificateResponse certificateResponse = null;
try {
CertificateCacheManager cacheManager = CertificateCacheManagerImpl.getInstance();
certificateResponse = cacheManager.getCertificateBySerial(serialNumber);
if (certificateResponse == null) {
try {
CertificateManagementDAOFactory.openConnection();
certificateResponse = certDao.retrieveCertificate(serialNumber, tenantId);
} catch (SQLException e) {
String errorMsg = "Error when making a connection to the database.";
throw new KeystoreException(errorMsg, e);
} finally {
CertificateManagementDAOFactory.closeConnection();
}
if (certificateResponse != null && certificateResponse.getCertificate() != null) {
Certificate certificate = (Certificate) Serializer.deserialize(certificateResponse.getCertificate());
if (certificate instanceof X509Certificate) {
X509Certificate x509cert = (X509Certificate) certificate;
String commonName = CertificateGenerator.getCommonName(x509cert);
certificateResponse.setCommonName(commonName);
cacheManager.addCertificateBySerial(serialNumber, certificateResponse);
}
}
}
} catch (CertificateManagementDAOException e) {
String errorMsg = "Error when retrieving certificate from the the database for the serial number: " +
serialNumber;
throw new KeystoreException(errorMsg, e);
} catch (ClassNotFoundException | IOException e) {
String errorMsg = "Error when de-serializing saved certificate.";
throw new KeystoreException(errorMsg, e);
}
return certificateResponse;
}
public CertificateResponse getCertificateBySerial(String serialNumber) throws KeystoreException {
CertificateResponse certificateResponse = null;
try {

@ -187,6 +187,104 @@ public interface RoleManagementService {
defaultValue = "5")
@QueryParam("limit") int limit);
@GET
@Path("/visible/{metaKey}")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = "GET",
value = "Getting the List of Visible Roles",
notes = "WSO2 IoTS supports role-based access control (RBAC) and role management. Using this API you can the list of roles that are in WSO2 IoTS.\n" +
"Note: Internal roles, roles created for service-providers, and application related roles will not be given in the output.",
tags = "Role Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:roles:view")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully fetched the list of roles in WSO2 IoTS.",
response = RoleList.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "ETag",
description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource has been modified the last time.\n" +
"Used by caches, or in conditional requests."),
}),
@ApiResponse(
code = 304,
message = "Not Modified. \n Empty body because the client already has the latest version of the " +
"requested resource."),
@ApiResponse(
code = 404,
message = "Not Found. \n The specified resource does not exist.\n",
response = ErrorResponse.class),
@ApiResponse(
code = 406,
message = "Not Acceptable.\n The requested media type is not supported",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Server error occurred while fetching the list of roles" +
" assigned to the specified user.",
response = ErrorResponse.class)
})
Response getVisibleRole(
@ApiParam(
name = "filter",
value = "Provide a character or a few characters in the role name.",
required = false)
@QueryParam("filter") String filter,
@ApiParam(
name = "user-store",
value = "The name of the UserStore you wish to get the list of roles.",
required = false)
@QueryParam("user-store") String userStoreName,
@ApiParam(
name = "If-Modified-Since",
value = "Checks if the requested variant was modified, since the specified date-time." +
"Provide the value in the following format: EEE, d MMM yyyy HH:mm:ss Z.\n" +
"Example: Mon, 05 Jan 2014 15:10:00 +0200",
required = false)
@HeaderParam("If-Modified-Since") String ifModifiedSince,
@ApiParam(
name = "offset",
value = "The starting pagination index for the complete list of qualified items.",
required = false,
defaultValue = "0")
@QueryParam("offset") int offset,
@ApiParam(
name = "limit",
value = "Provide how many role details you require from the starting pagination index/offset.",
required = false,
defaultValue = "5")
@QueryParam("limit") int limit,
@ApiParam(
name = "username",
value = "The username of the user.",
required = true,
defaultValue = "admin")
@QueryParam("username") String username,
@ApiParam(
name = "domain",
value = "The domain name of the user store.",
required = false)
@QueryParam("domain") String domain,
@ApiParam(
name = "metaKey",
value = "Key of the metadata",
required = true)
@PathParam("metaKey") String metaKey);
@GET
@Path("/filter/{prefix}")
@ApiOperation(

@ -29,6 +29,7 @@ import io.entgra.device.mgt.core.device.mgt.common.group.mgt.RoleDoesNotExistExc
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import io.entgra.device.mgt.core.device.mgt.common.Device;
import io.entgra.device.mgt.core.device.mgt.common.DeviceIdentifier;
@ -48,6 +49,8 @@ import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.util.RequestV
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.util.DeviceMgtAPIUtils;
import io.entgra.device.mgt.core.policy.mgt.common.PolicyAdministratorPoint;
import io.entgra.device.mgt.core.policy.mgt.common.PolicyManagementException;
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
@ -56,6 +59,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class GroupManagementServiceImpl implements GroupManagementService {
@ -109,8 +113,18 @@ public class GroupManagementServiceImpl implements GroupManagementService {
request.setGroupName(name);
request.setOwner(owner);
request.setDepth(depth);
PaginationResult deviceGroupsResult = DeviceMgtAPIUtils.getGroupManagementProviderService()
.getGroupsWithHierarchy(currentUser, request, requireGroupProps);
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
UserRealm realmService = DeviceMgtAPIUtils.getRealmService().getTenantUserRealm(tenantId);
String[] roles = realmService.getUserStoreManager().getRoleListOfUser(currentUser);
boolean hasAdminRole = Arrays.asList(roles).contains(DEFAULT_ADMIN_ROLE);
PaginationResult deviceGroupsResult;
if (hasAdminRole) {
deviceGroupsResult = DeviceMgtAPIUtils.getGroupManagementProviderService()
.getGroupsWithHierarchy(null, request, requireGroupProps);
} else{
deviceGroupsResult = DeviceMgtAPIUtils.getGroupManagementProviderService()
.getGroupsWithHierarchy(currentUser, request, requireGroupProps);
}
DeviceGroupList deviceGroupList = new DeviceGroupList();
deviceGroupList.setList(deviceGroupsResult.getData());
deviceGroupList.setCount(deviceGroupsResult.getRecordsTotal());
@ -119,6 +133,10 @@ public class GroupManagementServiceImpl implements GroupManagementService {
String error = "Error occurred while retrieving groups with hierarchy.";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
} catch (UserStoreException e) {
String msg = "Error occurred while getting user realm.";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@ -457,8 +475,8 @@ public class GroupManagementServiceImpl implements GroupManagementService {
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (GroupAlreadyExistException e) {
String msg = "Group already exists with name : " + groups.getName() + ".";
log.warn(msg);
String msg = "Group already exists with name : " + groups.getName() + " Try with another group name.";
log.error(msg, e);
return Response.status(Response.Status.CONFLICT).entity(msg).build();
} catch (RoleDoesNotExistException e) {
return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();

@ -17,7 +17,13 @@
*/
package io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.MetadataManagementException;
import io.entgra.device.mgt.core.device.mgt.common.group.mgt.GroupManagementException;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.Metadata;
import org.apache.commons.logging.Log;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.base.MultitenantConstants;
@ -97,6 +103,96 @@ public class RoleManagementServiceImpl implements RoleManagementService {
}
}
@GET
@Path("/visible/{metaKey}")
@Override
public Response getVisibleRole(
@QueryParam("filter") String filter,
@QueryParam("user-store") String userStore,
@HeaderParam("If-Modified-Since") String ifModifiedSince,
@QueryParam("offset") int offset,
@QueryParam("limit") int limit,
@QueryParam("username") String username,
@QueryParam("domain") String domain,
@PathParam("metaKey") String metaKey) {
RequestValidationUtil.validatePaginationParameters(offset, limit);
if (limit == 0){
limit = Constants.DEFAULT_PAGE_LIMIT;
}
if (domain != null && !domain.isEmpty()) {
username = domain + '/' + username;
}
Metadata metadata;
List<String> visibleRoles;
RoleList visibleRoleList = new RoleList();
try {
metadata = DeviceMgtAPIUtils.getMetadataManagementService().retrieveMetadata(metaKey);
String metaValue = metadata.getMetaValue();
JSONParser parser = new JSONParser();
JSONObject jsonObject = (JSONObject) parser.parse(metaValue);
boolean decision = (boolean) jsonObject.get(Constants.IS_USER_ABLE_TO_VIEW_ALL_ROLES);
if (decision) {
if (userStore == null || "".equals(userStore)){
userStore = PRIMARY_USER_STORE;
}
try {
visibleRoles = getRolesFromUserStore(filter, userStore);
visibleRoleList.setList(visibleRoles);
visibleRoles = FilteringUtil.getFilteredList(getRolesFromUserStore(filter, userStore), offset, limit);
visibleRoleList.setList(visibleRoles);
return Response.status(Response.Status.OK).entity(visibleRoleList).build();
} catch (UserStoreException e) {
String msg = "Error occurred while retrieving roles from the underlying user stores";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
} else {
try {
UserStoreManager userStoreManager = DeviceMgtAPIUtils.getUserStoreManager();
if (!userStoreManager.isExistingUser(username)) {
if (log.isDebugEnabled()) {
log.debug("User by username: " + username + " does not exist for role retrieval.");
}
String msg = "User by username: " + username + " does not exist for role retrieval.";
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
}
visibleRoleList.setList(getFilteredVisibleRoles(userStoreManager, username));
return Response.status(Response.Status.OK).entity(visibleRoleList).build();
} catch (UserStoreException e) {
String msg = "Error occurred while trying to retrieve roles of the user '" + username + "'";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
}
} catch (MetadataManagementException e) {
String msg = "Error occurred while getting the metadata entry for metaKey:" + metaKey;
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (ParseException e) {
String msg = "Error occurred while parsing JSON metadata: " + e.getMessage();
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
}
}
private List<String> getFilteredVisibleRoles(UserStoreManager userStoreManager, String username)
throws UserStoreException {
String[] roleListOfUser;
roleListOfUser = userStoreManager.getRoleListOfUser(username);
List<String> filteredRoles = new ArrayList<>();
for (String role : roleListOfUser) {
if (!(role.startsWith("Internal/") || role.startsWith("Authentication/"))) {
filteredRoles.add(role);
}
}
return filteredRoles;
}
@GET
@Path("/filter/{prefix}")
@Override
@ -542,6 +638,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
@Consumes(MediaType.WILDCARD)
@Override
public Response deleteRole(@PathParam("roleName") String roleName, @QueryParam("user-store") String userStoreName) {
String roleToDelete = roleName;
if (userStoreName != null && !userStoreName.isEmpty()) {
roleName = userStoreName + "/" + roleName;
}
@ -549,6 +646,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
try {
final UserRealm userRealm = DeviceMgtAPIUtils.getUserRealm();
final UserStoreManager userStoreManager = userRealm.getUserStoreManager();
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
if (!userStoreManager.isExistingRole(roleName)) {
String msg = "No role exists with the name : " + roleName ;
return Response.status(404).entity(msg).build();
@ -558,16 +656,18 @@ public class RoleManagementServiceImpl implements RoleManagementService {
if (log.isDebugEnabled()) {
log.debug("Deleting the role in user store");
}
userStoreManager.deleteRole(roleName);
// Delete all authorizations for the current role before deleting
authorizationManager.clearRoleAuthorization(roleName);
DeviceMgtAPIUtils.getGroupManagementProviderService().deleteRoleAndRoleGroupMapping(roleName, roleToDelete, tenantId, userStoreManager, authorizationManager);
return Response.status(Response.Status.OK).build();
} catch (UserStoreException e) {
String msg = "Error occurred while deleting the role '" + roleName + "'";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (GroupManagementException e) {
String msg = "Error occurred while deleting group-role mapping records";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
}
@ -597,7 +697,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
userStoreManager.updateUserListOfRole(roleName, usersToDelete, usersToAdd);
return Response.status(Response.Status.OK).entity("Role '" + roleName + "' has " +
"successfully been updated with the user list")
"successfully been updated with the user list")
.build();
} catch (UserStoreException e) {
String msg = "Error occurred while updating the users of the role '" + roleName + "'";

@ -455,7 +455,7 @@ public class UserManagementServiceImpl implements UserManagementService {
userList = new ArrayList<>(users.size());
BasicUserInfo user;
for (String username : users) {
if (Constants.APIM_RESERVED_USER.equals(username)) {
if (Constants.APIM_RESERVED_USER.equals(username) || Constants.RESERVED_USER.equals(username)) {
continue;
}
user = getBasicUserInfo(username);
@ -520,6 +520,7 @@ public class UserManagementServiceImpl implements UserManagementService {
}
if (commonUsers != null) {
commonUsers.remove(Constants.APIM_RESERVED_USER);
commonUsers.remove(Constants.RESERVED_USER);
}
if (!skipSearch(commonUsers) && StringUtils.isNotEmpty(firstName)) {
@ -695,7 +696,7 @@ public class UserManagementServiceImpl implements UserManagementService {
userList = new ArrayList<>();
UserInfo user;
for (String username : users) {
if (Constants.APIM_RESERVED_USER.equals(username)) {
if (Constants.APIM_RESERVED_USER.equals(username) || Constants.RESERVED_USER.equals(username)) {
continue;
}
user = new UserInfo();

@ -31,7 +31,11 @@ import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.DeviceGroupList;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.api.admin.GroupManagementAdminService;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.util.RequestValidationUtil;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.util.DeviceMgtAPIUtils;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.apache.commons.lang.StringUtils;
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
@ -40,6 +44,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Arrays;
public class GroupManagementAdminServiceImpl implements GroupManagementAdminService {
@ -94,13 +99,25 @@ public class GroupManagementAdminServiceImpl implements GroupManagementAdminServ
@DefaultValue("5") @QueryParam("limit") int limit) {
try {
RequestValidationUtil.validatePaginationParameters(offset, limit);
String currentUser = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
GroupPaginationRequest request = new GroupPaginationRequest(offset, limit);
request.setGroupName(name);
request.setOwner(owner);
request.setStatus(status);
request.setDepth(depth);
PaginationResult deviceGroupsResult = DeviceMgtAPIUtils.getGroupManagementProviderService()
.getGroupsWithHierarchy(null, request, requireGroupProps);
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
UserRealm realmService = DeviceMgtAPIUtils.getRealmService().getTenantUserRealm(tenantId);
String[] roles = realmService.getUserStoreManager().getRoleListOfUser(currentUser);
boolean isAdmin = DEFAULT_ADMIN_ROLE.equals(currentUser);
boolean hasAdminRole = Arrays.asList(roles).contains(DEFAULT_ADMIN_ROLE);
PaginationResult deviceGroupsResult;
if (StringUtils.isBlank(currentUser) || isAdmin || hasAdminRole) {
deviceGroupsResult = DeviceMgtAPIUtils.getGroupManagementProviderService()
.getGroupsWithHierarchy(null, request, requireGroupProps);
} else {
deviceGroupsResult = DeviceMgtAPIUtils.getGroupManagementProviderService()
.getGroupsWithHierarchy(currentUser, request, requireGroupProps);
}
DeviceGroupList deviceGroupList = new DeviceGroupList();
deviceGroupList.setList(deviceGroupsResult.getData());
deviceGroupList.setCount(deviceGroupsResult.getRecordsTotal());
@ -109,6 +126,10 @@ public class GroupManagementAdminServiceImpl implements GroupManagementAdminServ
String error = "Error occurred while retrieving groups with hierarchy.";
log.error(error, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build();
} catch (UserStoreException e) {
String msg = "Error occurred while getting user realm.";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@ -166,8 +187,8 @@ public class GroupManagementAdminServiceImpl implements GroupManagementAdminServ
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
} catch (GroupAlreadyExistException e) {
String msg = "Group already exists with name : " + group.getName() + ".";
log.warn(msg);
String msg = "Group already exists with name : " + group.getName() + " Try with another group name.";
log.error(msg, e);
return Response.status(Response.Status.CONFLICT).entity(msg).build();
} catch (RoleDoesNotExistException e) {
return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();

@ -31,13 +31,15 @@ public class Constants {
public static final String USER_CLAIM_DEVICES = "http://wso2.org/claims/devices";
public static final String PRIMARY_USER_STORE = "PRIMARY";
public static final String APIM_RESERVED_USER = "apim_reserved_user";
public static final String DEFAULT_STREAM_VERSION = "1.0.0";
public static final String RESERVED_USER = "reserved_user";
public static final String DEFAULT_STREAM_VERSION = "1.0.0";
public static final String SCOPE = "scope";
public static final String JDBC_USERSTOREMANAGER = "org.wso2.carbon.user.core.jdbc.JDBCUserStoreManager";
public static final String DEFAULT_SIMPLE_DATE_FORMAT = "EEE, d MMM yyyy HH:mm:ss Z";
public static final int DEFAULT_PAGE_LIMIT = 50;
public static final String FORWARD_SLASH = "/";
public static final String ANDROID = "android";
public static final String IS_USER_ABLE_TO_VIEW_ALL_ROLES = "isUserAbleToViewAllRoles";
public static final String ANDROID_POLICY_VALIDATOR = "io.entgra.proprietary.uem.platform.android." +
"core.polcy.AndroidPolicyPayloadValidator";
public static final String IOS = "ios";

@ -134,6 +134,8 @@ public final class DeviceManagementConstants {
public static final String LAST_NAME = "last-name";
public static final String TENANT_ADMIN_USERNAME = "tenant-admin-username";
public static final String TENANT_ADMIN_PASSWORD = "tenant-admin-password";
public static final int OTP_DEFAULT_EXPIRY_SECONDS = 3600;
}
public static final class EventServices {

@ -25,6 +25,7 @@ public class QREnrollmentDetails {
String username;
String enrollmentMode;
Map<String, String> customValues;
int tokenExpiry;
public Map<String, String> getCustomValues() {
return customValues;
@ -45,4 +46,12 @@ public class QREnrollmentDetails {
public String getEnrollmentMode() { return enrollmentMode; }
public void setEnrollmentMode(String enrollmentMode) { this.enrollmentMode = enrollmentMode; }
public int getTokenExpiry() {
return tokenExpiry;
}
public void setTokenExpiry(int tokenExpiry) {
this.tokenExpiry = tokenExpiry;
}
}

@ -19,5 +19,5 @@
package io.entgra.device.mgt.core.device.mgt.common.otp.mgt;
public enum OTPEmailTypes {
USER_VERIFY, DEVICE_ENROLLMENT
USER_VERIFY, DEVICE_ENROLLMENT, USER_INVITE, REMOTE_SESSION
}

@ -35,7 +35,8 @@ public interface OTPManagementService {
* @throws OTPManagementException if error occurred whle verifying validity of the OPT
* @throws BadRequestException if found an null value for OTP
*/
OneTimePinDTO isValidOTP(String oneTimeToken) throws OTPManagementException, BadRequestException;
OneTimePinDTO isValidOTP(String oneTimeToken, boolean requireRenewal) throws
OTPManagementException, BadRequestException;
/**
* Invalidate the OTP and send welcome mail
@ -59,8 +60,7 @@ public interface OTPManagementService {
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;
OneTimePinDTO generateOneTimePin(OneTimePinDTO oneTimePinData, boolean persistPin) throws OTPManagementException;
OneTimePinDTO getRenewedOtpByEmailAndMailType(String email, String emailType) throws OTPManagementException;

@ -156,7 +156,12 @@ public interface DeviceManagementConfigService {
value = "The properties list using for query a device",
required = true)
@QueryParam("properties")
String properties);
String properties,
@ApiParam(
name = "withAccessToken",
value = "Whether to use access token or otp token for device configuration")
@QueryParam("withAccessToken")
boolean withAccessToken);
@PUT
@Path("/device/transfer")

@ -21,6 +21,10 @@ import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.OTPManagementException;
import io.entgra.device.mgt.core.device.mgt.common.otp.mgt.OTPEmailTypes;
import io.entgra.device.mgt.core.device.mgt.common.otp.mgt.dto.OneTimePinDTO;
import io.entgra.device.mgt.core.device.mgt.common.spi.OTPManagementService;
import io.entgra.device.mgt.core.device.mgt.config.api.beans.ErrorResponse;
import io.entgra.device.mgt.core.device.mgt.config.api.service.DeviceManagementConfigService;
import io.entgra.device.mgt.core.device.mgt.config.api.util.DeviceMgtAPIUtils;
@ -77,7 +81,8 @@ public class DeviceManagementConfigServiceImpl implements DeviceManagementConfig
@Path("/configurations")
@Produces(MediaType.APPLICATION_JSON)
public Response getConfiguration(@HeaderParam("token") String token,
@QueryParam("properties") String properties) {
@QueryParam("properties") String properties,
@QueryParam("withAccessToken") boolean withAccessToken) {
DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
try {
if (token == null || token.isEmpty()) {
@ -102,7 +107,8 @@ public class DeviceManagementConfigServiceImpl implements DeviceManagementConfig
deviceProps.put("token", token);
DeviceConfiguration devicesConfiguration =
dms.getDeviceConfiguration(deviceProps);
setAccessTokenToDeviceConfigurations(devicesConfiguration);
if (withAccessToken) setAccessTokenToDeviceConfigurations(devicesConfiguration);
else setOTPTokenToDeviceConfigurations(devicesConfiguration);
return Response.status(Response.Status.OK).entity(devicesConfiguration).build();
} catch (DeviceManagementException e) {
String msg = "Error occurred while retrieving configurations";
@ -214,6 +220,33 @@ public class DeviceManagementConfigServiceImpl implements DeviceManagementConfig
}
}
private void setOTPTokenToDeviceConfigurations(DeviceConfiguration deviceConfiguration)
throws DeviceManagementException {
OneTimePinDTO oneTimePinData = new OneTimePinDTO();
oneTimePinData.setEmail(OTPEmailTypes.DEVICE_ENROLLMENT.toString());
oneTimePinData.setEmailType(OTPEmailTypes.DEVICE_ENROLLMENT.toString());
oneTimePinData.setUsername(deviceConfiguration.getDeviceOwner());
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(
deviceConfiguration.getTenantDomain(), true);
oneTimePinData.setTenantId(PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId());
PrivilegedCarbonContext.endTenantFlow();
OTPManagementService otpManagementService = DeviceMgtAPIUtils.getOtpManagementService();
try {
OneTimePinDTO oneTimePinDTO = otpManagementService.generateOneTimePin(oneTimePinData, true);
if (oneTimePinDTO == null) {
String msg = "Null value returned when generating OTP token for " + oneTimePinData.getOtpToken();
log.error(msg);
throw new DeviceManagementException(msg);
}
deviceConfiguration.setAccessToken(oneTimePinDTO.getOtpToken());
} catch (OTPManagementException ex) {
String msg = "Error occurred while generating one time pin: " + ex.getMessage();
log.error(msg, ex);
throw new DeviceManagementException(msg, ex);
}
}
@Override
@Path("/tenants")
@GET

@ -21,6 +21,7 @@ package io.entgra.device.mgt.core.device.mgt.config.api.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import io.entgra.device.mgt.core.device.mgt.common.spi.OTPManagementService;
import io.entgra.device.mgt.core.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.user.core.service.RealmService;
@ -34,6 +35,8 @@ public class DeviceMgtAPIUtils {
private static DeviceManagementProviderService deviceManagementProviderService = null;
private static RealmService realmService = null;
private static OTPManagementService otpManagementService = null;
public static DeviceManagementProviderService getDeviceManagementService() {
if (deviceManagementProviderService == null) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
@ -48,6 +51,19 @@ public class DeviceMgtAPIUtils {
return deviceManagementProviderService;
}
public static OTPManagementService getOtpManagementService() {
if (otpManagementService == null) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
otpManagementService = (OTPManagementService) ctx.getOSGiService(OTPManagementService.class, null);
if (otpManagementService == null) {
String msg = "OTP Management Service has not initialized.";
log.error(msg);
throw new IllegalStateException(msg);
}
}
return otpManagementService;
}
public static RealmService getRealmService() {
if (realmService == null) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();

@ -156,6 +156,15 @@ public interface GroupDAO {
*/
void deleteGroupsMapping(List<Integer> groupIds, int tenantId) throws GroupManagementDAOException;
/**
* Delete mappings of Device Groups.
*
* @param role of Device Groups.
* @param tenantId of the role.
* @throws GroupManagementDAOException on error during deletion of mappings of groups
*/
void deleteGroupsMapping(String role, int tenantId) throws GroupManagementDAOException;
/**
* Delete existing Device Groups.
*
@ -212,6 +221,19 @@ public interface GroupDAO {
*/
List<DeviceGroup> getGroups(GroupPaginationRequest paginationRequest, int tenantId) throws GroupManagementDAOException;
/**
* Get paginated list of Device Groups in tenant with specified device group ids.
*
* @param paginationRequest to filter results.
* @param deviceGroupIds of groups required.
* @param tenantId of user's tenant.
* @param isWithParentPath of user's ParentPath.
* @return List of all Device Groups in tenant.
* @throws GroupManagementDAOException
*/
List<DeviceGroup> getGroups(GroupPaginationRequest paginationRequest, List<Integer> deviceGroupIds,
int tenantId, boolean isWithParentPath) throws GroupManagementDAOException;
/**
* Get paginated list of Device Groups in tenant with specified device group ids.
*

@ -108,7 +108,7 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
@Override
public List<DeviceGroup> getGroups(GroupPaginationRequest request, List<Integer> deviceGroupIds,
int tenantId) throws GroupManagementDAOException {
int tenantId) throws GroupManagementDAOException {
int deviceGroupIdsCount = deviceGroupIds.size();
if (deviceGroupIdsCount == 0) {
return new ArrayList<>();
@ -169,6 +169,73 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
throw new GroupManagementDAOException(msg, e);
}
}
@Override
public List<DeviceGroup> getGroups(GroupPaginationRequest request, List<Integer> deviceGroupIds,
int tenantId, boolean isWithParentPath) throws GroupManagementDAOException {
int deviceGroupIdsCount = deviceGroupIds.size();
if (deviceGroupIdsCount == 0) {
return new ArrayList<>();
}
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "SELECT ID, DESCRIPTION, GROUP_NAME, OWNER, STATUS, PARENT_PATH, PARENT_GROUP_ID FROM DM_GROUP WHERE TENANT_ID = ?";
if (StringUtils.isNotBlank(request.getGroupName())) {
sql += " AND GROUP_NAME LIKE ?";
}
if (StringUtils.isNotBlank(request.getOwner())) {
sql += " AND OWNER LIKE ?";
}
if (StringUtils.isNotBlank(request.getParentPath())) {
if(isWithParentPath){
sql += " AND PARENT_PATH LIKE ?";
}
}
sql += " AND ID IN (";
for (int i = 0; i < deviceGroupIdsCount; i++) {
sql += (deviceGroupIdsCount - 1 != i) ? "?," : "?";
}
sql += ")";
if (request.getRowCount() != 0) {
sql += " LIMIT ? OFFSET ?";
}
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int paramIndex = 1;
stmt.setInt(paramIndex++, tenantId);
if (StringUtils.isNotBlank(request.getGroupName())) {
stmt.setString(paramIndex++, request.getGroupName() + "%");
}
if (StringUtils.isNotBlank(request.getOwner())) {
stmt.setString(paramIndex++, request.getOwner() + "%");
}
if (StringUtils.isNotBlank(request.getParentPath())) {
if(isWithParentPath){
stmt.setString(paramIndex++, request.getParentPath());
}
}
for (Integer deviceGroupId : deviceGroupIds) {
stmt.setInt(paramIndex++, deviceGroupId);
}
if (request.getRowCount() != 0) {
stmt.setInt(paramIndex++, request.getRowCount());
stmt.setInt(paramIndex, request.getStartIndex());
}
List<DeviceGroup> deviceGroupList = new ArrayList<>();
try (ResultSet resultSet = stmt.executeQuery()) {
while (resultSet.next()) {
deviceGroupList.add(GroupManagementDAOUtil.loadGroup(resultSet));
}
}
return deviceGroupList;
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving groups of groups IDs " + deviceGroupIds.toString()
+ " in tenant: " + tenantId;
log.error(msg);
throw new GroupManagementDAOException(msg, e);
}
}
@Override
public int addGroup(DeviceGroup deviceGroup, int tenantId) throws GroupManagementDAOException {
@ -376,7 +443,7 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "UPDATE DM_GROUP SET DESCRIPTION = ?, GROUP_NAME = ?, OWNER = ?, STATUS = ?, "
+ "PARENT_PATH = ? WHERE ID = ? AND TENANT_ID = ?";
+ "PARENT_PATH = ?, PARENT_GROUP_ID = ? WHERE ID = ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)){
for (DeviceGroup deviceGroup : deviceGroups) {
stmt.setString(1, deviceGroup.getDescription());
@ -384,8 +451,9 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
stmt.setString(3, deviceGroup.getOwner());
stmt.setString(4, deviceGroup.getStatus());
stmt.setString(5, deviceGroup.getParentPath());
stmt.setInt(6, deviceGroup.getGroupId());
stmt.setInt(7, tenantId);
stmt.setInt(6, deviceGroup.getParentGroupId());
stmt.setInt(7, deviceGroup.getGroupId());
stmt.setInt(8, tenantId);
stmt.addBatch();
}
stmt.executeBatch();
@ -476,6 +544,23 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
}
}
@Override
public void deleteGroupsMapping(String role, int tenantId) throws GroupManagementDAOException {
try {
Connection conn = GroupManagementDAOFactory.getConnection();
String sql = "DELETE FROM DM_ROLE_GROUP_MAP WHERE ROLE = ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, role);
stmt.setInt(2, tenantId);
stmt.executeUpdate();
}
} catch (SQLException e) {
String msg = "Error occurred while removing record from group-role mapping.";
log.error(msg);
throw new GroupManagementDAOException(msg, e);
}
}
@Override
public void deleteGroups(List<Integer> groupIds, int tenantId) throws GroupManagementDAOException {
try {
@ -1201,7 +1286,7 @@ public abstract class AbstractGroupDAOImpl implements GroupDAO {
}
@Override
@Override
public List<Device> getAllDevicesOfGroup(String groupName, int tenantId) throws GroupManagementDAOException {
Connection conn;
List<Device> devices;

@ -480,6 +480,7 @@ public class OperationManagerImpl implements OperationManager {
int failAttempts = 0;
while (true) {
try {
OperationManagementDAOFactory.beginTransaction();
operationMappingDAO.updateOperationMapping(operation.getId(), device.getEnrolmentInfo().getId(),
io.entgra.device.mgt.core.device.mgt.core.dto.operation.mgt.Operation.PushNotificationStatus.SCHEDULED);
OperationManagementDAOFactory.commitTransaction();
@ -502,6 +503,11 @@ public class OperationManagerImpl implements OperationManager {
} catch (InterruptedException ignore) {
break;
}
} catch (TransactionManagementException ex) {
log.error("Error occurred while initiating the transaction", ex);
break;
} finally {
OperationManagementDAOFactory.closeConnection();
}
}
} catch (Exception e) {

@ -18,6 +18,7 @@
package io.entgra.device.mgt.core.device.mgt.core.otp.mgt.dao.impl;
import io.entgra.device.mgt.core.device.mgt.common.DeviceManagementConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.DBConnectionException;
@ -56,7 +57,8 @@ public class GenericOTPManagementDAOImpl extends AbstractDAOImpl implements OTPM
+ "META_INFO, "
+ "CREATED_AT,"
+ "TENANT_ID,"
+ "USERNAME) VALUES (?, ?, ?, ?, ?, ?, ?)";
+ "USERNAME, "
+ "EXPIRY_TIME) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
try {
Connection conn = this.getDBConnection();
Calendar calendar = Calendar.getInstance();
@ -70,6 +72,8 @@ public class GenericOTPManagementDAOImpl extends AbstractDAOImpl implements OTPM
stmt.setTimestamp(5, timestamp);
stmt.setInt(6, oneTimePinDTO.getTenantId());
stmt.setString(7, oneTimePinDTO.getUsername());
stmt.setInt(8, oneTimePinDTO.getExpiryTime() == 0
? DeviceManagementConstants.OTPProperties.OTP_DEFAULT_EXPIRY_SECONDS : oneTimePinDTO.getExpiryTime());
stmt.addBatch();
}
stmt.executeBatch();

@ -127,7 +127,8 @@ public class OTPManagementServiceImpl implements OTPManagementService {
}
@Override
public OneTimePinDTO isValidOTP(String oneTimeToken) throws OTPManagementException, BadRequestException {
public OneTimePinDTO isValidOTP(String oneTimeToken, boolean requireRenewal) throws OTPManagementException,
BadRequestException {
if (StringUtils.isBlank(oneTimeToken)){
String msg = "Received blank OTP to verify. OTP: " + oneTimeToken;
log.error(msg);
@ -151,17 +152,19 @@ public class OTPManagementServiceImpl implements OTPManagementService {
oneTimePinDTO.getCreatedAt().getTime() + oneTimePinDTO.getExpiryTime() * 1000L);
if (currentTimestamp.after(expiredTimestamp)) {
String renewedOTP = UUID.randomUUID().toString();
renewOTP(oneTimePinDTO, renewedOTP);
Gson gson = new Gson();
Tenant tenant = gson.fromJson(oneTimePinDTO.getMetaInfo(), Tenant.class);
if (requireRenewal) {
String renewedOTP = UUID.randomUUID().toString();
renewOTP(oneTimePinDTO, renewedOTP);
Gson gson = new Gson();
Tenant tenant = gson.fromJson(oneTimePinDTO.getMetaInfo(), Tenant.class);
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);
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;
}
return oneTimePinDTO;
@ -234,9 +237,6 @@ public class OTPManagementServiceImpl implements OTPManagementService {
}
}
}
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
OneTimePinDTO oneTimePinDTO;
List<OneTimePinDTO> oneTimePinDTOList = new ArrayList<>();
Properties props = new Properties();
props.setProperty("enrollment-steps", enrollmentSteps.toString());
try {
@ -244,16 +244,11 @@ public class OTPManagementServiceImpl implements OTPManagementService {
for (String username : deviceEnrollmentInvitation.getUsernames()) {
String emailAddress = DeviceManagerUtil.getUserClaimValue(
username, DeviceManagementConstants.User.CLAIM_EMAIL_ADDRESS);
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));
props.setProperty("username", username);
props.setProperty("otp-token", oneTimePinDTO.getOtpToken());
sendMail(props, emailAddress, DeviceManagementConstants.EmailAttributes.USER_ENROLLMENT_TEMPLATE);
}
this.otpManagementDAO.addOTPData(oneTimePinDTOList);
ConnectionManagerUtil.commitDBTransaction();
} catch (UserStoreException e) {
String msg = "Error occurred while getting claim values to invite user";
@ -267,11 +262,6 @@ public class OTPManagementServiceImpl implements OTPManagementService {
String msg = "SQL Error occurred when adding OPT data to send device enrollment Invitation.";
log.error(msg, e);
throw new OTPManagementException(msg, e);
} catch (OTPManagementDAOException e) {
ConnectionManagerUtil.rollbackDBTransaction();
String msg = "Error occurred while saving the OTP data.";
log.error(msg, e);
throw new OTPManagementException(msg, e);
} finally {
ConnectionManagerUtil.closeDBConnection();
}
@ -279,27 +269,17 @@ public class OTPManagementServiceImpl implements OTPManagementService {
/**
* Create One Time Token
* @param email email
* @param emailType email type
* @param userName username
* @param metaDataObj meta data object
* @param tenantId tenant Id
* @param oneTimePinDTO Data related to the one time pin
* @return {@link OneTimePinDTO}
*/
@Override
public OneTimePinDTO generateOneTimePin(String email, String emailType, String userName, Object metaDataObj,
int tenantId, boolean persistPin) throws OTPManagementException {
public OneTimePinDTO generateOneTimePin(OneTimePinDTO oneTimePinDTO, boolean persistPin) throws OTPManagementException {
String otpValue = UUID.randomUUID().toString();
Gson gson = new Gson();
String metaInfo = gson.toJson(metaDataObj);
String metaInfo = gson.toJson(oneTimePinDTO.getMetaInfo());
OneTimePinDTO oneTimePinDTO = new OneTimePinDTO();
oneTimePinDTO.setEmail(email);
oneTimePinDTO.setTenantId(tenantId);
oneTimePinDTO.setUsername(userName);
oneTimePinDTO.setEmailType(emailType);
oneTimePinDTO.setMetaInfo(metaInfo);
oneTimePinDTO.setOtpToken(otpValue);

@ -156,6 +156,7 @@ import java.lang.reflect.Type;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
@ -466,6 +467,8 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
if (log.isDebugEnabled()) {
log.debug("Modifying enrollment for device: " + device.getId() + " of type '" + device.getType() + "'");
}
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername();
DeviceManager deviceManager = this.getDeviceManager(device.getType());
DeviceIdentifier deviceIdentifier = new DeviceIdentifier(device.getDeviceIdentifier(), device.getType());
if (deviceManager == null) {
@ -494,6 +497,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
enrollmentDAO.updateEnrollment(device.getEnrolmentInfo(), tenantId);
DeviceManagementDAOFactory.commitTransaction();
log.info("Device enrolled successfully", deviceEnrolmentLogContextBuilder.setDeviceId(String.valueOf(currentDevice.getId())).setDeviceType(String.valueOf(currentDevice.getType())).setOwner(currentDevice.getEnrolmentInfo().getOwner()).setOwnership(String.valueOf(currentDevice.getEnrolmentInfo().getOwnership())).setTenantID(String.valueOf(tenantId)).setTenantDomain(tenantDomain).setUserName(userName).build());
this.removeDeviceFromCache(deviceIdentifier);
} catch (DeviceManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
@ -1069,7 +1073,15 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
dateDiff = endDate.getTime() - device.getEnrolmentInfo().getDateOfEnrolment();
}
}
long dateInDays = TimeUnit.DAYS.convert(dateDiff, TimeUnit.MILLISECONDS);
// Convert dateDiff to days as a decimal value
double dateDiffInDays = (double) dateDiff / (24 * 60 * 60 * 1000);
if (dateDiffInDays % 1 >= 0.9) {
dateDiffInDays = Math.ceil(dateDiffInDays);
}
long dateInDays = (long) dateDiffInDays;
double cost = (tenantCost.getCost() / 365) * dateInDays;
totalCost += cost;
device.setCost(Math.round(cost * 100.0) / 100.0);
@ -1136,9 +1148,13 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
long difference_In_Days = (difference_In_Time / (1000 * 60 * 60 * 24)) % 365;
if (difference_In_Time % (1000 * 60 * 60 * 24) >= 0.9 * (1000 * 60 * 60 * 24)) {
difference_In_Days++;
}
for (int i = 1; i <= difference_In_Years; i++) {
List<Device> allDevicesPerYear = new ArrayList<>();
LocalDateTime oneYearAfterStart = startDate.toLocalDateTime().plusYears(1);
LocalDateTime oneYearAfterStart = startDate.toLocalDateTime().plusYears(1).with(LocalTime.of(23, 59, 59));;
Timestamp newStartDate;
Timestamp newEndDate;
@ -1147,14 +1163,12 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
remainingDaysConsidered = true;
oneYearAfterStart = startDate.toLocalDateTime();
newEndDate = endDate;
} else if (Timestamp.valueOf(oneYearAfterStart).getTime() >= endDate.getTime()) {
newEndDate = Timestamp.valueOf(oneYearAfterStart);
} else {
oneYearAfterStart = startDate.toLocalDateTime().plusYears(1);
oneYearAfterStart = startDate.toLocalDateTime().plusYears(1).with(LocalTime.of(23, 59, 59));;
newEndDate = Timestamp.valueOf(oneYearAfterStart);
}
} else {
oneYearAfterStart = startDate.toLocalDateTime().plusYears(1);
oneYearAfterStart = startDate.toLocalDateTime().plusYears(1).with(LocalTime.of(23, 59, 59));;
newEndDate = Timestamp.valueOf(oneYearAfterStart);
}
@ -1177,7 +1191,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
allDevices.addAll(billingResponse.getDevice());
totalCost = totalCost + billingResponse.getTotalCostPerYear();
deviceCount = deviceCount + billingResponse.getDeviceCount();
LocalDateTime nextStartDate = oneYearAfterStart.plusDays(1);
LocalDateTime nextStartDate = oneYearAfterStart.plusDays(1).with(LocalTime.of(00, 00, 00));
startDate = Timestamp.valueOf(nextStartDate);
}

@ -30,6 +30,8 @@ import io.entgra.device.mgt.core.device.mgt.common.group.mgt.GroupAlreadyExistEx
import io.entgra.device.mgt.core.device.mgt.common.group.mgt.GroupManagementException;
import io.entgra.device.mgt.core.device.mgt.common.group.mgt.GroupNotExistException;
import io.entgra.device.mgt.core.device.mgt.common.group.mgt.RoleDoesNotExistException;
import org.wso2.carbon.user.api.AuthorizationManager;
import org.wso2.carbon.user.api.UserStoreManager;
import java.util.List;
@ -57,7 +59,7 @@ public interface GroupManagementProviderService {
* @param defaultPermissions of the default role
* @throws GroupManagementException
*/
void createGroupWithRoles(DeviceGroupRoleWrapper groups, String defaultRole, String[] defaultPermissions) throws GroupManagementException, GroupAlreadyExistException, RoleDoesNotExistException;
void createGroupWithRoles(DeviceGroupRoleWrapper groups, String defaultRole, String[] defaultPermissions) throws GroupAlreadyExistException,GroupManagementException, RoleDoesNotExistException;
/**
* Update existing device group.
@ -79,6 +81,18 @@ public interface GroupManagementProviderService {
*/
boolean deleteGroup(int groupId, boolean isDeleteChildren) throws GroupManagementException;
/**
* Delete existing device group.
*
* @param role to be deleted with the userStore name.
* @param roleToDelete to delete the role.
* @param tenantId to belongs to roles.
* @param userStoreManager with details.
* @param authorizationManager with details.
* @throws GroupManagementException
*/
void deleteRoleAndRoleGroupMapping(String role, String roleToDelete, int tenantId, UserStoreManager userStoreManager, AuthorizationManager authorizationManager) throws GroupManagementException;
/**
* Get the device group provided the device group id.
*

@ -35,7 +35,6 @@ import io.entgra.device.mgt.core.device.mgt.core.dao.GroupManagementDAOFactory;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.netbeans.lib.cvsclient.commandLine.command.status;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.context.PrivilegedCarbonContext;
@ -46,14 +45,13 @@ import io.entgra.device.mgt.core.device.mgt.common.exceptions.DeviceManagementEx
import io.entgra.device.mgt.core.device.mgt.common.exceptions.DeviceNotFoundException;
import io.entgra.device.mgt.core.device.mgt.common.GroupPaginationRequest;
import io.entgra.device.mgt.core.device.mgt.common.PaginationResult;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.TrackerAlreadyExistException;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.TransactionManagementException;
import io.entgra.device.mgt.core.device.mgt.core.event.config.GroupAssignmentEventOperationExecutor;
import io.entgra.device.mgt.core.device.mgt.core.geo.task.GeoFenceEventOperationManager;
import io.entgra.device.mgt.core.device.mgt.core.internal.DeviceManagementDataHolder;
import io.entgra.device.mgt.core.device.mgt.core.operation.mgt.OperationMgtConstants;
import io.entgra.device.mgt.core.device.mgt.core.util.DeviceManagerUtil;
import io.entgra.device.mgt.core.device.mgt.core.util.HttpReportingUtil;
import org.wso2.carbon.user.api.AuthorizationManager;
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
@ -148,7 +146,7 @@ public class GroupManagementProviderServiceImpl implements GroupManagementProvid
}
}
public void createGroupWithRoles(DeviceGroupRoleWrapper groups, String defaultRole, String[] defaultPermissions) throws GroupManagementException {
public void createGroupWithRoles(DeviceGroupRoleWrapper groups, String defaultRole, String[] defaultPermissions) throws GroupAlreadyExistException, GroupManagementException {
if (groups == null) {
String msg = "Received incomplete data for createGroup";
log.error(msg);
@ -181,7 +179,7 @@ public class GroupManagementProviderServiceImpl implements GroupManagementProvid
}
GroupManagementDAOFactory.commitTransaction();
} else {
throw new GroupManagementException("Group exist with name " + groups.getName());
throw new GroupAlreadyExistException("Group already exists with name : " + groups.getName() + " Try with another group name.");
}
} catch (GroupManagementDAOException e) {
GroupManagementDAOFactory.rollbackTransaction();
@ -312,6 +310,13 @@ public class GroupManagementProviderServiceImpl implements GroupManagementProvid
newParentPath = DeviceGroupConstants.HierarchicalGroup.SEPERATOR;
}
childrenGroup.setParentPath(newParentPath);
if (!newParentPath.equals(DeviceGroupConstants.HierarchicalGroup.SEPERATOR)) {
String[] groupIds = newParentPath.split(DeviceGroupConstants.HierarchicalGroup.SEPERATOR);
int latestGroupId = Integer.parseInt(groupIds[groupIds.length - 1]);
childrenGroup.setParentGroupId(latestGroupId);
} else {
childrenGroup.setParentGroupId(0);
}
}
}
}
@ -352,6 +357,40 @@ public class GroupManagementProviderServiceImpl implements GroupManagementProvid
}
}
/**
* {@inheritDoc}
*/
@Override
public void deleteRoleAndRoleGroupMapping(String roleName, String roleToDelete, int tenantId, UserStoreManager userStoreManager, AuthorizationManager authorizationManager) throws GroupManagementException {
if (log.isDebugEnabled()) {
log.debug("Delete roles");
}
try {
GroupManagementDAOFactory.beginTransaction();
groupDAO.deleteGroupsMapping(roleToDelete, tenantId);
userStoreManager.deleteRole(roleName);
// Delete all authorizations for the current role before deleting
authorizationManager.clearRoleAuthorization(roleName);
GroupManagementDAOFactory.commitTransaction();
} catch (UserStoreException e) {
GroupManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while deleting the role '" + roleName + "'";
log.error(msg, e);
throw new GroupManagementException(msg, e);
} catch (TransactionManagementException e) {
String msg = "Error occurred while initiating transaction.";
log.error(msg, e);
throw new GroupManagementException(msg, e);
} catch (GroupManagementDAOException e) {
GroupManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while deleting the role";
log.error(msg, e);
throw new GroupManagementException(msg, e);
} finally {
GroupManagementDAOFactory.closeConnection();
}
}
/**
* {@inheritDoc}
*/
@ -518,7 +557,7 @@ public class GroupManagementProviderServiceImpl implements GroupManagementProvid
@Override
public PaginationResult getGroupsWithHierarchy(String username, GroupPaginationRequest request,
boolean requireGroupProps) throws GroupManagementException {
boolean requireGroupProps) throws GroupManagementException {
if (request == null) {
String msg = "Received incomplete data for retrieve groups with hierarchy";
log.error(msg);
@ -527,6 +566,7 @@ public class GroupManagementProviderServiceImpl implements GroupManagementProvid
if (log.isDebugEnabled()) {
log.debug("Get groups with hierarchy " + request.toString());
}
boolean isWithParentPath = false;
DeviceManagerUtil.validateGroupListPageSize(request);
List<DeviceGroup> rootGroups;
try {
@ -538,7 +578,7 @@ public class GroupManagementProviderServiceImpl implements GroupManagementProvid
} else {
List<Integer> allDeviceGroupIdsOfUser = getGroupIds(username);
GroupManagementDAOFactory.openConnection();
rootGroups = this.groupDAO.getGroups(request, allDeviceGroupIdsOfUser, tenantId);
rootGroups = this.groupDAO.getGroups(request, allDeviceGroupIdsOfUser, tenantId, isWithParentPath);
}
String parentPath;
List<DeviceGroup> childrenGroups;
@ -1359,7 +1399,7 @@ public class GroupManagementProviderServiceImpl implements GroupManagementProvid
* @throws GroupManagementDAOException on error during population of group properties.
*/
private void createGroupWithChildren(DeviceGroup parentGroup, List<DeviceGroup> childrenGroups,
boolean requireGroupProps, int tenantId, int depth, int counter) throws GroupManagementDAOException {
boolean requireGroupProps, int tenantId, int depth, int counter) throws GroupManagementDAOException {
if (childrenGroups.isEmpty() || depth == counter) {
return;
}

@ -74,17 +74,18 @@ public class JWTClientExtensionDataHolder {
public void setRealmService(RealmService realmService) {
this.realmService = realmService;
this.setTenantManager(realmService);
setTenantManager(realmService != null ?
realmService.getTenantManager() : null);
}
private void setTenantManager(RealmService realmService) {
if (realmService == null) {
throw new IllegalStateException("Realm service is not initialized properly");
}
this.tenantManager = realmService.getTenantManager();
private void setTenantManager(TenantManager tenantManager) {
this.tenantManager = tenantManager;
}
public TenantManager getTenantManager() {
if (tenantManager == null) {
throw new IllegalStateException("Tenant manager is not initialized properly");
}
return tenantManager;
}
}

@ -19,7 +19,6 @@
package io.entgra.device.mgt.core.ui.request.interceptor;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.entgra.device.mgt.core.ui.request.interceptor.beans.AuthData;
@ -28,12 +27,17 @@ import io.entgra.device.mgt.core.ui.request.interceptor.util.HandlerUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import io.entgra.device.mgt.core.ui.request.interceptor.beans.ProxyResponse;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import io.entgra.device.mgt.core.device.mgt.common.DeviceManagementConstants;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.OTPManagementException;
import io.entgra.device.mgt.core.device.mgt.common.otp.mgt.OTPEmailTypes;
import io.entgra.device.mgt.core.device.mgt.common.otp.mgt.dto.OneTimePinDTO;
import io.entgra.device.mgt.core.device.mgt.common.spi.OTPManagementService;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.service.RealmService;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
@ -55,71 +59,28 @@ public class DefaultTokenHandler extends HttpServlet {
HttpSession httpSession = req.getSession(false);
if (httpSession != null) {
AuthData authData = (AuthData) httpSession.getAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY);
if (authData == null) {
HandlerUtil.sendUnAuthorizeResponse(resp);
return;
String userWithDomain = (String) httpSession.getAttribute(HandlerConstants.USERNAME_WITH_DOMAIN);
String[] userNameParts = userWithDomain.split("@");
OneTimePinDTO oneTimePinData = new OneTimePinDTO();
oneTimePinData.setEmail(OTPEmailTypes.REMOTE_SESSION.toString());
oneTimePinData.setEmailType(OTPEmailTypes.REMOTE_SESSION.toString());
oneTimePinData.setUsername(userNameParts[0]);
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
RealmService realmService = (RealmService) ctx.getOSGiService(RealmService.class, null);
try {
oneTimePinData.setTenantId(realmService.getTenantManager().getTenantId(userNameParts[1]));
} catch (UserStoreException e) {
throw new RuntimeException(e);
}
AuthData defaultAuthData = (AuthData) httpSession
.getAttribute(HandlerConstants.SESSION_DEFAULT_AUTH_DATA_KEY);
if (defaultAuthData != null) {
HandlerUtil.handleSuccess(resp, constructSuccessProxyResponse(defaultAuthData.getAccessToken()));
return;
}
String clientId = authData.getClientId();
String clientSecret = authData.getClientSecret();
String queryString = req.getQueryString();
String scopeString = "";
if (StringUtils.isNotEmpty(queryString)) {
scopeString = req.getParameter("scopes");
if (scopeString != null) {
scopeString = "?scopes=" + scopeString;
}
}
String iotsCoreUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR
+ System.getProperty(HandlerConstants.IOT_GW_HOST_ENV_VAR)
+ HandlerConstants.COLON + HandlerUtil.getGatewayPort(req.getScheme());
String tokenUrl = iotsCoreUrl + "/api/device-mgt/v1.0/devices/" + clientId
+ "/" + clientSecret + "/default-token" + scopeString;
HttpGet defaultTokenRequest = new HttpGet(tokenUrl);
defaultTokenRequest
.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
defaultTokenRequest
.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString());
ProxyResponse tokenResultResponse = HandlerUtil.execute(defaultTokenRequest);
if (tokenResultResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
log.error("Error occurred while invoking the API to get default token data.");
HandlerUtil.handleError(resp, tokenResultResponse);
return;
}
String tokenResult = tokenResultResponse.getData();
if (tokenResult == null) {
log.error("Invalid default token response is received.");
HandlerUtil.handleError(resp, tokenResultResponse);
return;
}
JsonParser jsonParser = new JsonParser();
JsonElement jTokenResult = jsonParser.parse(tokenResult);
if (jTokenResult.isJsonObject()) {
JsonObject jTokenResultAsJsonObject = jTokenResult.getAsJsonObject();
AuthData newDefaultAuthData = new AuthData();
newDefaultAuthData.setClientId(clientId);
newDefaultAuthData.setClientSecret(clientSecret);
String defaultToken = jTokenResultAsJsonObject.get("accessToken").getAsString();
newDefaultAuthData.setAccessToken(defaultToken);
newDefaultAuthData.setRefreshToken(jTokenResultAsJsonObject.get("refreshToken").getAsString());
newDefaultAuthData.setScope(jTokenResultAsJsonObject.get("scopes").getAsString());
httpSession.setAttribute(HandlerConstants.SESSION_DEFAULT_AUTH_DATA_KEY, newDefaultAuthData);
HandlerUtil.handleSuccess(resp, constructSuccessProxyResponse(defaultToken));
oneTimePinData.setExpiryTime(DeviceManagementConstants.OTPProperties.OTP_DEFAULT_EXPIRY_SECONDS);
OTPManagementService otpManagementService = HandlerUtil.getOTPManagementService();
try {
oneTimePinData = otpManagementService.generateOneTimePin(oneTimePinData, true);
HandlerUtil.handleSuccess(resp, constructSuccessProxyResponse(oneTimePinData.getOtpToken()));
} catch (OTPManagementException e) {
log.error("Failed while generating remote session OTP for user " + userWithDomain, e);
HandlerUtil.handleError(resp, HttpStatus.SC_INTERNAL_SERVER_ERROR);
}
} else {
HandlerUtil.sendUnAuthorizeResponse(resp);

@ -120,6 +120,7 @@ public class UserHandler extends HttpServlet {
proxyResponse.setData(
jTokenResultAsJsonObject.get("username").getAsString().replaceAll("@carbon.super", ""));
HandlerUtil.handleSuccess(resp, proxyResponse);
httpSession.setAttribute(HandlerConstants.USERNAME_WITH_DOMAIN, jTokenResultAsJsonObject.get("username").getAsString());
log.info("Customer login", userLogContextBuilder.setUserName(proxyResponse.getData()).setUserRegistered(true).build());
}
} catch (IOException e) {

@ -106,4 +106,5 @@ public class HandlerConstants {
public static final String IOT_REPORTING_WEBAPP_HOST_ENV_VAR = "iot.reporting.webapp.host";
public static final String USER_SCOPES = "userScopes";
public static final String HUBSPOT_CHAT_URL = "api.hubapi.com";
public static final String USERNAME_WITH_DOMAIN = "usernameWithDomain";
}

@ -55,6 +55,8 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import io.entgra.device.mgt.core.ui.request.interceptor.beans.ProxyResponse;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import io.entgra.device.mgt.core.device.mgt.common.spi.OTPManagementService;
import org.xml.sax.SAXException;
import javax.servlet.http.HttpServletRequest;
@ -79,6 +81,8 @@ public class HandlerUtil {
private static boolean isLoginCacheInitialized = false;
private static AuthData authData;
private static OTPManagementService otpManagementService;
/***
*
* @param httpRequest - httpMethod e.g:- HttpPost, HttpGet
@ -751,4 +755,12 @@ public class HandlerUtil {
public static boolean isPropertyDefined(String property) {
return StringUtils.isEmpty(System.getProperty(property));
}
public static OTPManagementService getOTPManagementService() {
if (otpManagementService == null) {
otpManagementService = (OTPManagementService) PrivilegedCarbonContext
.getThreadLocalCarbonContext().getOSGiService(OTPManagementService.class, null);
}
return otpManagementService;
}
}

@ -35,6 +35,7 @@ import io.entgra.device.mgt.core.webapp.authenticator.framework.Utils.Utils;
import java.nio.charset.Charset;
import java.util.Base64;
import java.util.Properties;
import java.util.StringTokenizer;
public class BasicAuthAuthenticator implements WebappAuthenticator {
@ -50,15 +51,23 @@ public class BasicAuthAuthenticator implements WebappAuthenticator {
@Override
public boolean canHandle(Request request) {
/*
This is done to avoid every endpoint being able to use basic auth. Add the following to
the required web.xml of the web app.
This is done to avoid every web app being able to use basic auth. Add the following to
the required web.xml of the web app. This is a global config for a web app to allow all
contexts of the web app to use basic auth
<context-param>
<param-name>basicAuth</param-name>
<param-value>true</param-value>
</context-param>
Adding the basicAuthAllowList parameter allows to selectively allow some context paths in a
web app to use basic auth while all the other context remain unavailable with basic auth.
If this parameter is present, any context that requires basic auth must be specially
added as comma separated list to the param-value of basicAuthAllowList.
*/
if (!isAuthenticationSupported(request)) {
return false;
if (!isAllowListedForBasicAuth(request)) {
if (!isAuthenticationSupported(request)) {
return false;
}
}
if (request.getCoyoteRequest() == null || request.getCoyoteRequest().getMimeHeaders() == null) {
return false;
@ -75,6 +84,20 @@ public class BasicAuthAuthenticator implements WebappAuthenticator {
return false;
}
private boolean isAllowListedForBasicAuth(Request request) {
String param = request.getContext().findParameter("basicAuthAllowList");
if (param != null && !param.isEmpty()) {
//Add the nonSecured end-points to cache
String[] basicAuthAllowList = param.split(",");
for (String contexPath : basicAuthAllowList) {
if (request.getRequestURI().toString().endsWith(contexPath.trim())) {
return true;
}
}
}
return false;
}
@Override
public AuthenticationInfo authenticate(Request request, Response response) {
AuthenticationInfo authenticationInfo = new AuthenticationInfo();

@ -74,9 +74,17 @@ public class CertificateAuthenticator implements WebappAuthenticator {
// When there is a load balancer terminating mutual SSL, it should pass this header along and
// as the value of this header, the client certificate subject dn should be passed.
if (request.getHeader(PROXY_MUTUAL_AUTH_HEADER) != null) {
if (log.isDebugEnabled()) {
log.debug("PROXY_MUTUAL_AUTH_HEADER " + request.getHeader(PROXY_MUTUAL_AUTH_HEADER));
}
CertificateResponse certificateResponse = AuthenticatorFrameworkDataHolder.getInstance().
getCertificateManagementService().verifySubjectDN(request.getHeader(PROXY_MUTUAL_AUTH_HEADER));
authenticationInfo = checkCertificateResponse(certificateResponse);
if (log.isDebugEnabled()) {
log.debug("Certificate Serial : " + certificateResponse.getSerialNumber()
+ ", CN : " + certificateResponse.getCommonName()
+ " , username" + authenticationInfo.getUsername());
}
}
else if (request.getHeader(MUTUAL_AUTH_HEADER) != null) {
Object object = request.getAttribute(CLIENT_CERTIFICATE_ATTRIBUTE);
@ -89,7 +97,6 @@ public class CertificateAuthenticator implements WebappAuthenticator {
CertificateResponse certificateResponse = AuthenticatorFrameworkDataHolder.getInstance().
getCertificateManagementService().verifyPEMSignature(clientCertificate[0]);
authenticationInfo = checkCertificateResponse(certificateResponse);
} else {
authenticationInfo.setStatus(Status.FAILURE);
authenticationInfo.setMessage("No client certificate is present");

@ -49,8 +49,18 @@ public class OneTimeTokenAuthenticator implements WebappAuthenticator {
try {
OTPManagementService otpManagementService = AuthenticatorFrameworkDataHolder.getInstance()
.getOtpManagementService();
OneTimePinDTO validOTP = otpManagementService.isValidOTP(request.getHeader(Constants.HTTPHeaders
.ONE_TIME_TOKEN_HEADER));
OneTimePinDTO validOTP;
if (request.getRequestURI().toString().endsWith("cloud/download-url")
|| request.getRequestURI().toString().endsWith("cloud/tenant")) {
validOTP = otpManagementService.isValidOTP(request.getHeader(Constants.HTTPHeaders
.ONE_TIME_TOKEN_HEADER), true);
} else {
log.info("Validating OTP for enrollments PIN: " + request.getHeader(Constants
.HTTPHeaders.ONE_TIME_TOKEN_HEADER));
validOTP = otpManagementService.isValidOTP(request.getHeader(Constants.HTTPHeaders
.ONE_TIME_TOKEN_HEADER), false);
}
if (validOTP != null) {
authenticationInfo.setStatus(Status.CONTINUE);
authenticationInfo.setTenantId(validOTP.getTenantId());

@ -189,7 +189,7 @@
&lt;a href='https://entgra.io' target='_blank'&gt;
Entgra
&lt;/a&gt;
IoT Server 5.2.0 | &#169; 2023
UEM Server 5.3.0 | &#169; 2023
, All Rights Reserved.
</FooterText>
<AppTitle>Entgra</AppTitle>

@ -227,6 +227,19 @@
<Scope>perm:android:clear-application</Scope>
<Scope>perm:android:suspend-package</Scope>
<Scope>perm:android:alternate-install</Scope>
<Scope>perm:ios:lock</Scope>
<Scope>perm:ios:location</Scope>
<Scope>perm:ios:ring</Scope>
<Scope>perm:ios:clear-passcode</Scope>
<Scope>perm:ios:enterprise-wipe</Scope>
<Scope>perm:ios:notification</Scope>
<Scope>perm:ios:wipe-data</Scope>
<Scope>perm:ios:boolean-setting</Scope>
<Scope>perm:ios:wallpaper</Scope>
<Scope>perm:ios:app-attributes</Scope>
<Scope>perm:ios:app-configurations</Scope>
<Scope>perm:mac-os:restart</Scope>
<Scope>perm:mac-os:shut-down</Scope>
</Scopes>
<SSOConfiguration>
<Issuer>device-mgt</Issuer>

@ -325,12 +325,16 @@
<MetaDataConfiguration>
<WhiteLabelConfiguration>
<FooterText>
&lt;a href='https://entgra.io' target='_blank'&gt;
Entgra
&lt;/a&gt;
IoT Server 5.2.0 | &#169; 2023
, All Rights Reserved.
</FooterText>
&lt;a href='https://entgra.io' target='_blank'&gt;
Entgra
&lt;/a&gt;
{% if product_conf is defined %}
{{product_conf.server_name}} {{product_conf.server_version}} | &#169; {{product_conf.current_year}}
{% else %}
Entgra UEM Server
{% endif %}
, All Rights Reserved.
</FooterText>
<AppTitle>Entgra</AppTitle>
<WhiteLabelImages>
<StoragePath>repository/resources/whitelabel</StoragePath>

@ -37,7 +37,7 @@
</p>
<p style="font-size: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 5px 0px;">
You have been invited to enrol your device in Entgra IoT Server.
Click <a href="$base-url-https/self-register/devices/enroll?token=$otp-token">here</a> to begin device enrolment.</p>
Click <a href="$base-url-https/endpoint-mgt/devices/enroll">here</a> to begin device enrolment.</p>
<p style="font-length: 1em; font-family: Arial, Helvetica; line-height: 170%; color: #666666; margin: 5px 0px;">
Enrollment Steps are as below,

Loading…
Cancel
Save