diff --git a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/CertificateManagementAdminService.java b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/CertificateManagementAdminService.java index 6fed010f651..e32571150d1 100644 --- a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/CertificateManagementAdminService.java +++ b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/CertificateManagementAdminService.java @@ -344,6 +344,46 @@ public interface CertificateManagementAdminService { defaultValue = "12438035315552875930") @PathParam("serialNumber") String serialNumber); + @DELETE + @Path("/{serialNumber}/v2") + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + produces = MediaType.APPLICATION_JSON, + httpMethod = "DELETE", + value = "Deleting an SSL Certificate", + notes = "Delete an SSL certificate that's on the client end.", + tags = "Certificate Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = SCOPE, value = "perm:admin:certificates:delete") + }) + } + ) + @ApiResponses(value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully removed the certificate."), + @ApiResponse( + code = 400, + message = "Bad Request. \n Invalid request or validation error.", + response = ErrorResponse.class), + @ApiResponse( + code = 404, + message = "Not Found. \n The specified resource does not exist."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n " + + "Server error occurred while removing the certificate.", + response = ErrorResponse.class)}) + Response removeCertificateDep( + @ApiParam( + name = "serialNumber", + value = "The serial number of the certificate.\n" + + "NOTE: Make sure that a certificate with the serial number you provide exists in the server. If not, first add a certificate.", + required = true, + defaultValue = "12438035315552875930") + @PathParam("serialNumber") String serialNumber); + /** * Verify Certificate for the API security filter * diff --git a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/impl/CertificateManagementAdminServiceImpl.java b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/impl/CertificateManagementAdminServiceImpl.java index 5957b1b8cfd..ac7aacfa069 100644 --- a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/impl/CertificateManagementAdminServiceImpl.java +++ b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.cert.admin.api/src/main/java/org/wso2/carbon/certificate/mgt/cert/jaxrs/api/impl/CertificateManagementAdminServiceImpl.java @@ -166,6 +166,26 @@ public class CertificateManagementAdminServiceImpl implements CertificateManagem } } + @DELETE + @Deprecated + @Path("/{serialNumber}/v2") + public Response removeCertificateDep(@PathParam("serialNumber") String serialNumber) { + RequestValidationUtil.validateSerialNumber(serialNumber); + + CertificateManagementService certificateService = CertificateMgtAPIUtils.getCertificateManagementService(); + try { + certificateService.removeCertificate(serialNumber); + return Response.status(Response.Status.OK).entity( + "Certificate that carries the serial number '" + + serialNumber + "' has been removed").build(); + } catch (CertificateManagementException e) { + String msg = "Error occurred while converting PEM file to X509Certificate"; + log.error(msg, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + } + } + // @POST // @Path("/verify/ios") // public Response verifyIOSCertificate(@ApiParam(name = "certificate", value = "Mdm-Signature of the " + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java index 4fbc97f41b3..84e07d11c0b 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java @@ -299,6 +299,143 @@ public interface DeviceManagementService { @QueryParam("limit") int limit); + @GET + @ApiOperation( + produces = MediaType.APPLICATION_JSON, + httpMethod = "GET", + value = "Getting Details of Registered Devices", + notes = "Provides details of all the devices enrolled with WSO2 IoT Server.", + tags = "Device Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view") + }) + } + ) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK. \n Successfully fetched the list of devices.", + response = DeviceList.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 was last modified.\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.\n"), + @ApiResponse( + code = 400, + message = "The incoming request has more than one selection criteria defined via the query parameters.", + response = ErrorResponse.class), + @ApiResponse( + code = 404, + message = "The search criteria did not match any device registered with the server.", + response = ErrorResponse.class), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n The requested media type is not supported."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while fetching the device list.", + response = ErrorResponse.class) + }) + @Path("/v2") + Response getDevicesDep( + @ApiParam( + name = "name", + value = "The device name, such as shamu, bullhead or angler Nexus device names. ", + required = false) + @Size(max = 45) + String name, + @ApiParam( + name = "type", + value = "The device type, such as ios, android or windows.", + required = false) + @QueryParam("type") + @Size(max = 45) + String type, + @ApiParam( + name = "user", + value = "The username of the owner of the device.", + required = false) + @QueryParam("user") + String user, + @ApiParam( + name = "userPattern", + value = "The pattern of username of the owner of the device.", + required = false) + @QueryParam("userPattern") + String userPattern, + @ApiParam( + name = "role", + value = "A role of device owners. Ex : store-admin", + required = false) + @QueryParam("role") + @Size(max = 45) + String role, + @ApiParam( + name = "ownership", + allowableValues = "BYOD, COPE", + value = "Provide the ownership status of the device. The following values can be assigned:\n" + + "- BYOD: Bring Your Own Device\n" + + "- COPE: Corporate-Owned, Personally-Enabled", + required = false) + @QueryParam("ownership") + @Size(max = 45) + String ownership, + @ApiParam( + name = "status", + value = "Provide the device status details, such as active or inactive.", + required = false) + @QueryParam("status") + @Size(max = 45) + String status, + @ApiParam( + name = "groupId", + value = "Id of the group which device belongs", + required = false) + @QueryParam("groupId") + int groupId, + @ApiParam( + name = "since", + value = "Checks if the requested variant was created since the specified date-time.\n" + + "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) + @QueryParam("since") + String since, + @ApiParam( + name = "If-Modified-Since", + value = "Checks if the requested variant was modified, since the specified date-time.\n" + + "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 timestamp, + @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 device details you require from the starting pagination index/offset.", + required = false, + defaultValue = "5") + @QueryParam("limit") + int limit); + @GET @ApiOperation( produces = MediaType.APPLICATION_JSON, @@ -1185,6 +1322,107 @@ public interface DeviceManagementService { @QueryParam("owner") String owner); + @GET + @Path("/{type}/{id}/operations/v2") + @ApiOperation( + produces = MediaType.APPLICATION_JSON, + httpMethod = "GET", + value = "Getting Device Operation Details", + notes = "Get the details of operations carried out on a selected device.", + tags = "Device Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:operations") + }) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully fetched the list of operations scheduled for the device.", + response = Operation.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 was last modified" + + "Used by caches, or in conditional requests.")}), + @ApiResponse( + code = 303, + message = "See Other. \n " + + "The source can be retrieved from the URL specified in the location header.\n", + responseHeaders = { + @ResponseHeader( + name = "Content-Location", + description = "The Source URL of the document.")}), + @ApiResponse( + code = 304, + message = "Not Modified. \n " + + "Empty body because the client already has the latest version of the requested resource."), + @ApiResponse( + code = 400, + message = "Bad Request. \n Invalid request or validation error.", + response = ErrorResponse.class), + @ApiResponse( + code = 404, + message = "Not Found. \n The specified device does not exist.", + response = ErrorResponse.class), + @ApiResponse( + code = 406, + message = "Not Acceptable. \n The requested media type is not supported."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n " + + "Server error occurred while retrieving the operation list scheduled for the device.", + response = ErrorResponse.class) + }) + Response getDeviceOperationsDep( + @ApiParam( + name = "type", + value = "The device type name, such as ios, android, windows or fire-alarm.", + required = true) + @PathParam("type") + @Size(max = 45) + String type, + @ApiParam( + name = "id", + value = "The device identifier of the device you wish to get details.\n" + + "INFO: Make sure to add the ID of a device that is already registered with WSO2 IoTS.", + required = true) + @PathParam("id") + @Size(max = 45) + String id, + @ApiParam( + name = "If-Modified-Since", + value = "Checks if the requested variant was modified, since the specified date-time. \n" + + "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 activity details you require from the starting pagination index/offset.", + required = false, + defaultValue = "5") + @QueryParam("limit") + int limit); + @GET @Path("/{type}/{id}/effective-policy") @ApiOperation( diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java index 020c78469a0..b6a0397df08 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java @@ -269,6 +269,149 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { } } + @GET + @Path("/v2") + @Deprecated + @Override + public Response getDevicesDep( + @QueryParam("name") String name, + @QueryParam("type") String type, + @QueryParam("user") String user, + @QueryParam("userPattern") String userPattern, + @QueryParam("role") String role, + @QueryParam("ownership") String ownership, + @QueryParam("status") String status, + @QueryParam("groupId") int groupId, + @QueryParam("since") String since, + @HeaderParam("If-Modified-Since") String ifModifiedSince, + @QueryParam("offset") int offset, + @QueryParam("limit") int limit) { + try { + if (!StringUtils.isEmpty(name) && !StringUtils.isEmpty(role)) { + return Response.status(Response.Status.BAD_REQUEST).entity( + new ErrorResponse.ErrorResponseBuilder().setMessage("Request contains both name and role " + + "parameters. Only one is allowed " + + "at once.").build()).build(); + } + RequestValidationUtil.validatePaginationParameters(offset, limit); + DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService(); + DeviceAccessAuthorizationService deviceAccessAuthorizationService = + DeviceMgtAPIUtils.getDeviceAccessAuthorizationService(); + if (deviceAccessAuthorizationService == null) { + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity( + new ErrorResponse.ErrorResponseBuilder().setMessage("Device access authorization service is " + + "failed").build()).build(); + } + PaginationRequest request = new PaginationRequest(offset, limit); + PaginationResult result; + DeviceList devices = new DeviceList(); + + if (name != null && !name.isEmpty()) { + request.setDeviceName(name); + } + if (type != null && !type.isEmpty()) { + request.setDeviceType(type); + } + if (ownership != null && !ownership.isEmpty()) { + RequestValidationUtil.validateOwnershipType(ownership); + request.setOwnership(ownership); + } + if (status != null && !status.isEmpty()) { + RequestValidationUtil.validateStatus(status); + request.setStatus(status); + } + if (groupId != 0) { + request.setGroupId(groupId); + } + if (role != null && !role.isEmpty()) { + request.setOwnerRole(role); + } + + String authorizedUser = MultitenantUtils.getTenantAwareUsername(CarbonContext.getThreadLocalCarbonContext().getUsername()); + + if (deviceAccessAuthorizationService.isDeviceAdminUser()) { + if (user != null && !user.isEmpty()) { + request.setOwner(MultitenantUtils.getTenantAwareUsername(user)); + } else if (userPattern != null && !userPattern.isEmpty()) { + request.setOwnerPattern(userPattern); + } + } else { + if (user != null && !user.isEmpty()) { + user = MultitenantUtils.getTenantAwareUsername(user); + if (user.equals(authorizedUser)) { + request.setOwner(user); + } else { + String msg = "User '" + authorizedUser + "' is not authorized to retrieve devices of '" + user + + "' user"; + log.error(msg); + return Response.status(Response.Status.UNAUTHORIZED).entity( + new ErrorResponse.ErrorResponseBuilder().setCode(401l).setMessage(msg).build()).build(); + } + } else { + request.setOwner(authorizedUser); + } + } + + if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { + Date sinceDate; + SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z"); + try { + sinceDate = format.parse(ifModifiedSince); + } catch (ParseException e) { + return Response.status(Response.Status.BAD_REQUEST).entity( + new ErrorResponse.ErrorResponseBuilder().setMessage("Invalid date " + + "string is provided in 'If-Modified-Since' header").build()).build(); + } + request.setSince(sinceDate); + result = dms.getAllDevices(request); + + if (result == null || result.getData() == null || result.getData().size() <= 0) { + return Response.status(Response.Status.NOT_MODIFIED).entity("No device is modified " + + "after the timestamp provided in 'If-Modified-Since' header").build(); + } + } else if (since != null && !since.isEmpty()) { + Date sinceDate; + SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z"); + try { + sinceDate = format.parse(since); + } catch (ParseException e) { + return Response.status(Response.Status.BAD_REQUEST).entity( + new ErrorResponse.ErrorResponseBuilder().setMessage("Invalid date " + + "string is provided in 'since' filter").build()).build(); + } + request.setSince(sinceDate); + result = dms.getAllDevices(request); + + if (result == null || result.getData() == null || result.getData().size() <= 0) { + devices.setList(new ArrayList()); + devices.setCount(0); + return Response.status(Response.Status.OK).entity(devices).build(); + } + } else { + result = dms.getAllDevices(request); + int resultCount = result.getRecordsTotal(); + if (resultCount == 0) { + Response.status(Response.Status.OK).entity(devices).build(); + } + } + + devices.setList((List) result.getData()); + devices.setCount(result.getRecordsTotal()); + return Response.status(Response.Status.OK).entity(devices).build(); + } catch (DeviceManagementException e) { + String msg = "Error occurred while fetching all enrolled devices"; + log.error(msg, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + } catch (DeviceAccessAuthorizationException e) { + String msg = "Error occurred while checking device access authorization"; + log.error(msg, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + } + } + + @GET @Override @Path("/user-devices") @@ -611,6 +754,43 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { } } + @GET + @Path("/{type}/{id}/operations/v2") + @Deprecated + @Override + public Response getDeviceOperationsDep( + @PathParam("type") @Size(max = 45) String type, + @PathParam("id") @Size(max = 45) String id, + @HeaderParam("If-Modified-Since") String ifModifiedSince, + @QueryParam("offset") int offset, + @QueryParam("limit") int limit) + { + OperationList operationsList = new OperationList(); + String owner = CarbonContext.getThreadLocalCarbonContext().getUsername(); + RequestValidationUtil.validateOwnerParameter(owner); + RequestValidationUtil.validatePaginationParameters(offset, limit); + PaginationRequest request = new PaginationRequest(offset, limit); + request.setOwner(owner); + PaginationResult result; + DeviceManagementProviderService dms; + try { + RequestValidationUtil.validateDeviceIdentifier(type, id); + + dms = DeviceMgtAPIUtils.getDeviceManagementService(); + result = dms.getOperations(new DeviceIdentifier(id, type), request); + + operationsList.setList((List) result.getData()); + operationsList.setCount(result.getRecordsTotal()); + return Response.status(Response.Status.OK).entity(operationsList).build(); + } catch (OperationManagementException e) { + String msg = "Error occurred while fetching the operations for the '" + type + "' device, which " + + "carries the id '" + id + "'"; + log.error(msg, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + } + } + @GET @Path("/{type}/{id}/effective-policy") @Override diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java index c49ef81340b..56915c293ed 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java @@ -709,7 +709,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } finally { DeviceManagementDAOFactory.closeConnection(); } - if (requireDeviceInfo) { + if (requireDeviceInfo && !allDevices.isEmpty()) { paginationResult.setData(getAllDeviceInfo(allDevices)); } else { paginationResult.setData(allDevices);