diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index c63f6178c7..d9b454d1b4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -142,6 +142,51 @@ public class ControllerConstants { protected static final String EVENT_DEBUG_RULE_NODE_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_NODE\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; protected static final String EVENT_DEBUG_RULE_CHAIN_FILTER_OBJ = MARKDOWN_CODE_BLOCK_START + "{ \"eventType\": \"DEBUG_RULE_CHAIN\"," + DEBUG_FILTER_OBJ + MARKDOWN_CODE_BLOCK_END; + protected static final String IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION = "A Boolean value representing the Server SecurityInfo for future Bootstrap client mode settings. Values: 'true' for Bootstrap Server; 'false' for Lwm2m Server. "; + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION = + " {\n\"class org.thingsboard.server.common.data.Device\":{\n" + + " \"id\": \"null\",\n" + + " \"createdTime\":0,\n" + + " \"additionalInfo\":\"null\",\n" + + " \"tenantId\":\"null\",\n" + + " \"customerId\":\"null\",\n" + + " \"name\":\"LwRpk00000000\",\n" + + " \"type\":\"lwm2mProfileRpk\",\n" + + " \"label\":\"null\",\"" + + " \"deviceProfileId\":\"null\",\n" + + " \"deviceData\":\"null\",\n" + + " \"firmwareId\":\"null\",\n" + + " \"softwareId\":\"null\"\n" + + " },\n" + + " \"class org.thingsboard.server.common.data.security.DeviceCredentials\":{\n" + + " \"class_DeviceCredentials1\":{\n" + + " \"id\":\"null\",\n" + + " \"createdTime\":0,\n" + + " \"deviceId\":\"null|',\n" + + " \"credentialsType\":\"LWM2M_CREDENTIALS\",\n" + + " \"credentialsId\":\"LwRpk00000000\",\n" + + " \"credentialsValue\":{\n" + + " \"client\":{\n" + + " \"endpoint\":\"LwRpk00000000\",\n" + + " \"securityConfigClientMode\":\"RPK\",\n" + + " \"key\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\"\n" + + " },\n" + + " \"bootstrap\":{\n" + + " \"bootstrapServer\":{\n" + + " \"securityMode\":\"RPK\",\n" + + " \"clientPublicKeyOrId\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\",\n" + + " \"clientSecretKey\":\"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\"" + + " },\n" + + " \"lwm2mServer\":{\n" + + " \"securityMode\":\"RPK\",\n" + + " \"clientPublicKeyOrId\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\",\n" + + " \"clientSecretKey\":\"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + protected static final String FILTER_VALUE_TYPE = NEW_LINE + "## Value Type and Operations" + NEW_LINE + "Provides a hint about the data type of the entity field that is defined in the filter key. " + "The value type impacts the list of possible operations that you may use in the corresponding predicate. For example, you may use 'STARTS_WITH' or 'END_WITH', but you can't use 'GREATER_OR_EQUAL' for string values." + diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index 64537d9f5f..1117f78dc5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -16,6 +16,8 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; @@ -35,16 +37,28 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.Map; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; + @Slf4j @RestController @TbCoreComponent @RequestMapping("/api") public class Lwm2mController extends BaseController { + public static final String IS_BOOTSTRAP_SERVER = "isBootstrapServer"; + + @ApiOperation(value = "Get Lwm2m Bootstrap SecurityInfo (getLwm2mBootstrapSecurityInfo)", + notes = "Get the Lwm2m Bootstrap SecurityInfo object (of the current server) based on the provided isBootstrapServer parameter. If isBootstrapServer == true, get the parameters of the current Bootstrap Server. If isBootstrapServer == false, get the parameters of the current Lwm2m Server. Used for client settings when starting the client in Bootstrap mode. " + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, + produces = "application/json") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET) @ResponseBody - public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("isBootstrapServer") boolean bootstrapServer) throws ThingsboardException { + public ServerSecurityConfig getLwm2mBootstrapSecurityInfo( + @ApiParam(value = IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION) + @PathVariable(IS_BOOTSTRAP_SERVER) boolean bootstrapServer) throws ThingsboardException { try { return lwM2MServerSecurityInfoRepository.getServerSecurityInfo(bootstrapServer); } catch (Exception e) { @@ -52,13 +66,26 @@ public class Lwm2mController extends BaseController { } } + @ApiOperation(value = "Create Device (saveDevice) with credentials ", + notes = "\nCreate new Device with credentials (example with security mode: RPK\n" + + "\nRequestBody is the Map, Object>:\n" + + "\nThe first param of this map: Device\n"+ + "\n-- key1 = \"class org.thingsboard.server.common.data.Device\" - value1 = \"new Device()\"\n" + + "\nThe second param of this map: Device credentials\n" + + "\n-- key2 = \"class org.thingsboard.server.common.data.security.DeviceCredentials\" - value2 = \"new DeviceCredentials()\"\n" + + "\n- Example of the RequestBody with security mode: RPK:\n" + + "\n- " + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION + "\n" + + "\nWhen creating new device, platform generates Device Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address).\n" + + "\nAfter creating new device Device DeviceCredentials is added to new Device." + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/lwm2m/device-credentials", method = RequestMethod.POST) @ResponseBody - public Device saveDeviceWithCredentials(@RequestBody (required=false) Map, Object> deviceWithDeviceCredentials) throws ThingsboardException { + public Device saveDeviceWithCredentials(@ApiParam(value = DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION) + @RequestBody(required = false) Map, Object> deviceWithDeviceCredentials) throws ThingsboardException { ObjectMapper mapper = new ObjectMapper(); Device device = checkNotNull(mapper.convertValue(deviceWithDeviceCredentials.get(Device.class), Device.class)); - DeviceCredentials credentials = checkNotNull(mapper.convertValue( deviceWithDeviceCredentials.get(DeviceCredentials.class), DeviceCredentials.class)); + DeviceCredentials credentials = checkNotNull(mapper.convertValue(deviceWithDeviceCredentials.get(DeviceCredentials.class), DeviceCredentials.class)); try { device.setTenantId(getCurrentUser().getTenantId()); checkEntity(device.getId(), device, Resource.DEVICE); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java index 8220702ec8..0fe6be34eb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/ServerSecurityConfig.java @@ -15,17 +15,30 @@ */ package org.thingsboard.server.common.data.lwm2m; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; +@ApiModel @Data public class ServerSecurityConfig { - String host; - String securityHost; - Integer port; - Integer securityPort; - String serverPublicKey; + @ApiModelProperty(position = 1, value = "Is Bootstrap Server.", example = "true", readOnly = true) boolean bootstrapServerIs = true; - Integer clientHoldOffTime = 1; + @ApiModelProperty(position = 2, value = "Host No Security.", example = "0.0.0.0", readOnly = true) + String host; + @ApiModelProperty(position = 3, value = "Port No Security.", example = "5687", readOnly = true) + Integer port; + @ApiModelProperty(position = 4, value = "Host Security.", example = "0.0.0.0", readOnly = true) + String securityHost; + @ApiModelProperty(position = 5, value = "Port Security.", example = "5688", readOnly = true) + Integer securityPort; + @ApiModelProperty(position = 5, value = "Server short Id.", example = "111", readOnly = true) Integer serverId = 111; + @ApiModelProperty(position = 7, value = "Client Hold Off Time.", example = "1", readOnly = true) + Integer clientHoldOffTime = 1; + @ApiModelProperty(position = 8, value = "Server Public Key (formar base64).", example = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAZ0pSaGKHk/GrDaUDnQZpeEdGwX7m3Ws+U/kiVat\n" + + "+44sgk3c8g0LotfMpLlZJPhPwJ6ipXV+O1r7IZUjBs3LNA==", readOnly = true) + String serverPublicKey; + @ApiModelProperty(position = 9, value = "Bootstrap Server Account Timeout.", example = "0", readOnly = true) Integer bootstrapServerAccountTimeout = 0; } diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index 30dc57eeb7..376b08baab 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -1134,7 +1134,6 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { Map, Object> deviceCredentials = new ConcurrentHashMap<>(); deviceCredentials.put(Device.class, device); deviceCredentials.put(DeviceCredentials.class, credentials); -// return restTemplate.postForEntity(baseURL + "/api/lwm2m/device-credentials", deviceCredentials, Device.class).getBody(); ResponseEntity deviceOpt = restTemplate.postForEntity(baseURL + "/api/lwm2m/device-credentials", deviceCredentials, Device.class); return Optional.ofNullable(deviceOpt.getBody()); } catch (HttpClientErrorException exception) {