Add device transferring across tenants

feature/appm-store/pbac
Charitha Goonetilleke 5 years ago
parent 30d4a5707a
commit 2c7463a072

@ -18,6 +18,7 @@
package io.entgra.carbon.device.mgt.config.jaxrs.service; package io.entgra.carbon.device.mgt.config.jaxrs.service;
import org.wso2.carbon.device.mgt.common.DeviceTransferRequest;
import io.entgra.carbon.device.mgt.config.jaxrs.beans.ErrorResponse; import io.entgra.carbon.device.mgt.config.jaxrs.beans.ErrorResponse;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@ -33,12 +34,11 @@ import io.swagger.annotations.Tag;
import org.wso2.carbon.apimgt.annotations.api.Scope; import org.wso2.carbon.apimgt.annotations.api.Scope;
import org.wso2.carbon.apimgt.annotations.api.Scopes; import org.wso2.carbon.apimgt.annotations.api.Scopes;
import org.wso2.carbon.device.mgt.common.configuration.mgt.DeviceConfiguration; import org.wso2.carbon.device.mgt.common.configuration.mgt.DeviceConfiguration;
import org.wso2.carbon.device.mgt.common.search.PropertyMap;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam; import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST; import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
@ -63,7 +63,6 @@ import javax.ws.rs.core.Response;
) )
@Path("/configurations") @Path("/configurations")
@Api(value = "Device Management Configuration") @Api(value = "Device Management Configuration")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Scopes(scopes = { @Scopes(scopes = {
@Scope( @Scope(
@ -71,6 +70,12 @@ import javax.ws.rs.core.Response;
description = "", description = "",
key = "perm:view-configuration", key = "perm:view-configuration",
permissions = {"/device-mgt/platform-configurations/view"} permissions = {"/device-mgt/platform-configurations/view"}
),
@Scope(
name = "Manage configurations",
description = "",
key = "perm:manage-configuration",
permissions = {"/device-mgt/platform-configurations/manage"}
) )
} }
) )
@ -119,16 +124,74 @@ public interface DeviceManagementConfigService {
"fetching device configurations.", "fetching device configurations.",
response = ErrorResponse.class) response = ErrorResponse.class)
}) })
Response getConfiguration(@ApiParam( @Produces(MediaType.APPLICATION_JSON)
name = "token", Response getConfiguration(
value = "value for identify an already enrolled and authorized device", @ApiParam(
required = true) name = "token",
@HeaderParam("token") value = "value for identify an already enrolled and authorized device",
String token, required = true)
@ApiParam( @HeaderParam("token")
name = "properties", String token,
value = "The properties list using for query a device", @ApiParam(
required = true) name = "properties",
@QueryParam("properties") value = "The properties list using for query a device",
String properties); required = true)
@QueryParam("properties")
String properties);
@PUT
@Path("/transfer")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = "PUT",
value = "Transfer device to another tenant from super tenant",
notes = "This API is responsible for transfer device from super tenant to another tenant",
tags = "Device Management Configuration",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = "scope", value = "perm:manage-configuration")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully transferred the device.",
response = DeviceConfiguration.class,
responseContainer = "List",
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.Used by caches, or in " +
"conditional requests."),
}
),
@ApiResponse(
code = 400,
message = "Bad request.\n The request contains invalid parameters"),
@ApiResponse(
code = 401,
message = "Unauthorized.\n The requested is not authorized"),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Server error occurred while " +
"fetching device configurations.",
response = ErrorResponse.class)
})
@Produces(MediaType.APPLICATION_JSON)
Response transferDevices(
@ApiParam(
name = "Device Transfer Request",
value = "The device transfer request",
required = true)
DeviceTransferRequest deviceTransferRequest);
} }

@ -26,8 +26,10 @@ import io.entgra.carbon.device.mgt.config.jaxrs.service.DeviceManagementConfigSe
import io.entgra.carbon.device.mgt.config.jaxrs.util.DeviceMgtAPIUtils; import io.entgra.carbon.device.mgt.config.jaxrs.util.DeviceMgtAPIUtils;
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.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.AppRegistrationCredentials; import org.wso2.carbon.device.mgt.common.AppRegistrationCredentials;
import org.wso2.carbon.device.mgt.common.ApplicationRegistrationException; import org.wso2.carbon.device.mgt.common.ApplicationRegistrationException;
import org.wso2.carbon.device.mgt.common.DeviceTransferRequest;
import org.wso2.carbon.device.mgt.common.configuration.mgt.AmbiguousConfigurationException; import org.wso2.carbon.device.mgt.common.configuration.mgt.AmbiguousConfigurationException;
import org.wso2.carbon.device.mgt.common.configuration.mgt.DeviceConfiguration; import org.wso2.carbon.device.mgt.common.configuration.mgt.DeviceConfiguration;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
@ -41,16 +43,17 @@ import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientExceptio
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam; import javax.ws.rs.HeaderParam;
import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.Map; import java.util.Map;
@Path("/configurations") @Path("/configurations")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public class DeviceManagementConfigServiceImpl implements DeviceManagementConfigService { public class DeviceManagementConfigServiceImpl implements DeviceManagementConfigService {
@ -58,6 +61,7 @@ public class DeviceManagementConfigServiceImpl implements DeviceManagementConfig
@Override @Override
@GET @GET
@Produces(MediaType.APPLICATION_JSON)
public Response getConfiguration(@HeaderParam("token") String token, public Response getConfiguration(@HeaderParam("token") String token,
@QueryParam("properties") String properties) { @QueryParam("properties") String properties) {
DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService(); DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
@ -115,6 +119,41 @@ public class DeviceManagementConfigServiceImpl implements DeviceManagementConfig
} }
} }
@PUT
@Path("/transfer")
@Override
@Produces(MediaType.APPLICATION_JSON)
public Response transferDevices(DeviceTransferRequest deviceTransferRequest) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
int tenantId = ctx.getTenantId(false);
if (tenantId != -1234) {
return Response.status(Response.Status.FORBIDDEN).entity("Tenant '" + ctx.getTenantDomain(true) +
"' does not have privilege to transfer device").build();
}
DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService();
try {
List<String> devicesTransferred = dms.transferDeviceToTenant(deviceTransferRequest);
if (devicesTransferred.isEmpty()) {
String msg = "Devices are not enrolled to super tenant";
log.warn(msg);
return Response.status(Response.Status.BAD_REQUEST).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} else {
return Response.status(Response.Status.OK).entity(devicesTransferred).build();
}
} catch (DeviceManagementException e) {
String msg = "Error occurred while transferring device to tenant " +
deviceTransferRequest.getDestinationTenant();
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (DeviceNotFoundException e) {
log.error(e.getMessage(), e);
return Response.status(Response.Status.BAD_REQUEST).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(e.getMessage()).build()).build();
}
}
private String parseUriParamsToJSON(String uriParams) { private String parseUriParamsToJSON(String uriParams) {
uriParams = uriParams.replaceAll("=", "\":\""); uriParams = uriParams.replaceAll("=", "\":\"");
uriParams = uriParams.replaceAll("&", "\",\""); uriParams = uriParams.replaceAll("&", "\",\"");

@ -0,0 +1,48 @@
package org.wso2.carbon.device.mgt.common;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
/**
* Represents an individual configuration entry.
*/
@ApiModel(value = "DeviceTransferRequest", description = "This class carries all information related to device " +
"transfer from super tenant to another tenant.")
public class DeviceTransferRequest {
@ApiModelProperty(name = "deviceType", value = "Type of the device", required = true)
private String deviceType;
@ApiModelProperty(name = "deviceIds", value = "Ids of devices to transfer", required = true)
private List<String> deviceIds;
@ApiModelProperty(name = "destinationTenant", value = "Destination Tenant ID", required = true)
private String destinationTenant;
public String getDeviceType() {
return deviceType;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public List<String> getDeviceIds() {
return deviceIds;
}
public void setDeviceId(List<String> deviceIds) {
this.deviceIds = deviceIds;
}
public String getDestinationTenant() {
return destinationTenant;
}
public void setDestinationTenant(String destinationTenant) {
this.destinationTenant = destinationTenant;
}
}

@ -356,6 +356,10 @@
<groupId>org.powermock</groupId> <groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId> <artifactId>powermock-api-mockito</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.wso2.carbon.multitenancy</groupId>
<artifactId>org.wso2.carbon.tenant.mgt</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -45,6 +45,7 @@ import org.wso2.carbon.device.mgt.core.dto.DeviceType;
import org.wso2.carbon.device.mgt.core.geo.GeoCluster; import org.wso2.carbon.device.mgt.core.geo.GeoCluster;
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
import java.sql.SQLException;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -529,4 +530,7 @@ public interface DeviceDAO {
* @throws DeviceManagementDAOException * @throws DeviceManagementDAOException
*/ */
void deleteDevice(DeviceIdentifier deviceIdentifier, int tenantId) throws DeviceManagementDAOException; void deleteDevice(DeviceIdentifier deviceIdentifier, int tenantId) throws DeviceManagementDAOException;
boolean transferDevice(String deviceType, String deviceId, String owner, int destinationTenantId)
throws DeviceManagementDAOException, SQLException;
} }

@ -1937,4 +1937,49 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
DeviceManagementDAOUtil.cleanupResources(stmt, null); DeviceManagementDAOUtil.cleanupResources(stmt, null);
} }
} }
public boolean transferDevice(String deviceType, String deviceIdentifier, String owner, int destinationTenantId)
throws DeviceManagementDAOException, SQLException {
Connection conn = this.getConnection();
int deviceId = getDeviceId(conn, new DeviceIdentifier(deviceIdentifier, deviceType), -1234);
PreparedStatement stmt = null;
try {
String sql = "UPDATE DM_DEVICE SET TENANT_ID = ? WHERE ID = ? AND TENANT_ID = -1234";
stmt = conn.prepareStatement(sql);
stmt.setInt(1, destinationTenantId);
stmt.setInt(2, deviceId);
stmt.executeUpdate();
} catch (SQLException e) {
conn.rollback();
throw new DeviceManagementDAOException("Error occurred while removing device", e);
} finally {
DeviceManagementDAOUtil.cleanupResources(stmt, null);
}
try {
String sql = "UPDATE DM_DEVICE_PROPERTIES SET TENANT_ID = ? " +
"WHERE DEVICE_TYPE_NAME = ? AND DEVICE_IDENTIFICATION = ? AND TENANT_ID = -1234";
stmt = conn.prepareStatement(sql);
stmt.setInt(1, destinationTenantId);
stmt.setString(2, deviceType);
stmt.setString(3, deviceIdentifier);
stmt.executeUpdate();
} catch (SQLException e) {
throw new DeviceManagementDAOException("Error occurred while removing device", e);
} finally {
DeviceManagementDAOUtil.cleanupResources(stmt, null);
}
try {
String sql = "UPDATE DM_ENROLMENT SET TENANT_ID = ?, OWNER = ? WHERE DEVICE_ID = ? AND TENANT_ID = -1234";
stmt = conn.prepareStatement(sql);
stmt.setInt(1, destinationTenantId);
stmt.setString(2, owner);
stmt.setInt(3, deviceId);
stmt.executeUpdate();
} catch (SQLException e) {
throw new DeviceManagementDAOException("Error occurred while removing device", e);
} finally {
DeviceManagementDAOUtil.cleanupResources(stmt, null);
}
return true;
}
} }

@ -37,6 +37,7 @@ package org.wso2.carbon.device.mgt.core.service;
import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceTransferRequest;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
@ -760,4 +761,12 @@ public interface DeviceManagementProviderService {
DeviceConfiguration getDeviceConfiguration(Map<String, String> propertyMap) DeviceConfiguration getDeviceConfiguration(Map<String, String> propertyMap)
throws DeviceManagementException, DeviceNotFoundException, UnauthorizedDeviceAccessException, throws DeviceManagementException, DeviceNotFoundException, UnauthorizedDeviceAccessException,
AmbiguousConfigurationException; AmbiguousConfigurationException;
/**
* Transfer device from super tenant to another tenant
*
* @param deviceTransferRequest DTO of the transfer request
* @return tru if device transferee, otherwise false
*/
List<String> transferDeviceToTenant(DeviceTransferRequest deviceTransferRequest) throws DeviceManagementException, DeviceNotFoundException;
} }

@ -51,6 +51,7 @@ import org.wso2.carbon.device.mgt.analytics.data.publisher.exception.DataPublish
import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceEnrollmentInfoNotification; import org.wso2.carbon.device.mgt.common.DeviceEnrollmentInfoNotification;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceTransferRequest;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.DeviceManager; import org.wso2.carbon.device.mgt.common.DeviceManager;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException;
@ -129,6 +130,8 @@ import org.wso2.carbon.email.sender.core.EmailSendingFailedException;
import org.wso2.carbon.email.sender.core.EmailTransportNotConfiguredException; import org.wso2.carbon.email.sender.core.EmailTransportNotConfiguredException;
import org.wso2.carbon.email.sender.core.TypedValue; import org.wso2.carbon.email.sender.core.TypedValue;
import org.wso2.carbon.email.sender.core.service.EmailSenderService; import org.wso2.carbon.email.sender.core.service.EmailSenderService;
import org.wso2.carbon.stratos.common.beans.TenantInfoBean;
import org.wso2.carbon.tenant.mgt.services.TenantMgtAdminService;
import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.api.UserStoreException;
import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBContext;
@ -3503,6 +3506,65 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
} }
} }
@Override
public List<String> transferDeviceToTenant(DeviceTransferRequest deviceTransferRequest)
throws DeviceManagementException, DeviceNotFoundException {
if (log.isDebugEnabled()) {
log.debug("Attempting to transfer devices to '" +
deviceTransferRequest.getDestinationTenant() + "'");
}
List<String> enrolledDevices = new ArrayList<>();
DeviceIdentifier deviceIdentifier;
for (String deviceId : deviceTransferRequest.getDeviceIds()) {
deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(deviceTransferRequest.getDeviceType());
if (isEnrolled(deviceIdentifier)) {
enrolledDevices.add(deviceId);
} else {
log.warn("Device '" + deviceId + "' is not enrolled with super tenant. Hence excluding from transferring");
}
}
if (enrolledDevices.isEmpty()) {
throw new DeviceNotFoundException("No any enrolled device found to transfer");
}
int destinationTenantId;
String owner;
try {
TenantMgtAdminService tenantMgtAdminService = new TenantMgtAdminService();
TenantInfoBean tenantInfoBean = tenantMgtAdminService.getTenant(deviceTransferRequest.getDestinationTenant());
destinationTenantId = tenantInfoBean.getTenantId();
owner = tenantInfoBean.getAdmin();
} catch (Exception e) {
String msg = "Error getting destination tenant id and admin from domain'" +
deviceTransferRequest.getDestinationTenant() + "'";
log.error(msg);
throw new DeviceManagementException(msg, e);
}
try {
DeviceManagementDAOFactory.openConnection();
List<String> movedDevices = new ArrayList<>();
for (String deviceId : enrolledDevices) {
if (deviceDAO.transferDevice(deviceTransferRequest.getDeviceType(), deviceId, owner, destinationTenantId)){
movedDevices.add(deviceId);
} else {
log.warn("Device '" + deviceId + "' not transferred to tenant " + destinationTenantId);
}
}
DeviceManagementDAOFactory.commitTransaction();
return movedDevices;
} catch (SQLException | DeviceManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error in transferring devices to tenant '" + deviceTransferRequest.getDestinationTenant() + "'";
log.error(msg);
throw new DeviceManagementException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
/** /**
* Wrap the device configuration data into DeviceConfiguration bean * Wrap the device configuration data into DeviceConfiguration bean
* @param device Device queried using the properties * @param device Device queried using the properties

@ -1761,6 +1761,12 @@
<version>${tomcat.websocket.version}</version> <version>${tomcat.websocket.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.wso2.carbon.multitenancy</groupId>
<artifactId>org.wso2.carbon.tenant.mgt</artifactId>
<version>${carbon.multitenancy.version}</version>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

Loading…
Cancel
Save