68 changed files with 2211 additions and 41 deletions
@ -0,0 +1,257 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.service.device; |
|||
|
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import com.google.common.util.concurrent.MoreExecutors; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.util.StringUtils; |
|||
import org.thingsboard.server.common.data.DataConstants; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.DeviceProfile; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.id.UserId; |
|||
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|||
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
|||
import org.thingsboard.server.common.data.kv.StringDataEntry; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
import org.thingsboard.server.common.msg.TbMsgMetaData; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|||
import org.thingsboard.server.dao.attributes.AttributesService; |
|||
import org.thingsboard.server.dao.audit.AuditLogService; |
|||
import org.thingsboard.server.dao.device.DeviceCredentialsService; |
|||
import org.thingsboard.server.dao.device.DeviceDao; |
|||
import org.thingsboard.server.dao.device.DeviceProfileDao; |
|||
import org.thingsboard.server.dao.device.DeviceProvisionService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
import org.thingsboard.server.dao.device.provision.ProvisionFailedException; |
|||
import org.thingsboard.server.dao.device.provision.ProvisionRequest; |
|||
import org.thingsboard.server.dao.device.provision.ProvisionResponse; |
|||
import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus; |
|||
import org.thingsboard.server.dao.util.mapping.JacksonUtil; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.queue.TbQueueCallback; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.PartitionService; |
|||
import org.thingsboard.server.queue.provider.TbQueueProducerProvider; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.state.DeviceStateService; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
import java.util.concurrent.ExecutionException; |
|||
import java.util.concurrent.locks.ReentrantLock; |
|||
|
|||
|
|||
@Service |
|||
@Slf4j |
|||
@TbCoreComponent |
|||
public class DeviceProvisionServiceImpl implements DeviceProvisionService { |
|||
|
|||
protected TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> ruleEngineMsgProducer; |
|||
|
|||
private static final String DEVICE_PROVISION_STATE = "provisionState"; |
|||
private static final String PROVISIONED_STATE = "provisioned"; |
|||
|
|||
private final ReentrantLock deviceCreationLock = new ReentrantLock(); |
|||
|
|||
@Autowired |
|||
DeviceDao deviceDao; |
|||
|
|||
@Autowired |
|||
DeviceProfileDao deviceProfileDao; |
|||
|
|||
@Autowired |
|||
DeviceService deviceService; |
|||
|
|||
@Autowired |
|||
DeviceCredentialsService deviceCredentialsService; |
|||
|
|||
@Autowired |
|||
AttributesService attributesService; |
|||
|
|||
@Autowired |
|||
DeviceStateService deviceStateService; |
|||
|
|||
@Autowired |
|||
AuditLogService auditLogService; |
|||
|
|||
@Autowired |
|||
PartitionService partitionService; |
|||
|
|||
public DeviceProvisionServiceImpl(TbQueueProducerProvider producerProvider) { |
|||
ruleEngineMsgProducer = producerProvider.getRuleEngineMsgProducer(); |
|||
} |
|||
|
|||
@Override |
|||
public ProvisionResponse provisionDevice(ProvisionRequest provisionRequest) { |
|||
String provisionRequestKey = provisionRequest.getCredentials().getProvisionDeviceKey(); |
|||
String provisionRequestSecret = provisionRequest.getCredentials().getProvisionDeviceSecret(); |
|||
|
|||
if (StringUtils.isEmpty(provisionRequestKey) || StringUtils.isEmpty(provisionRequestSecret)) { |
|||
throw new ProvisionFailedException(ProvisionResponseStatus.NOT_FOUND.name()); |
|||
} |
|||
|
|||
DeviceProfile targetProfile = deviceProfileDao.findByProvisionDeviceKey(provisionRequestKey); |
|||
|
|||
if (targetProfile == null || targetProfile.getProfileData().getProvisionConfiguration() == null || |
|||
targetProfile.getProfileData().getProvisionConfiguration().getProvisionDeviceSecret() == null) { |
|||
throw new ProvisionFailedException(ProvisionResponseStatus.NOT_FOUND.name()); |
|||
} |
|||
|
|||
Device targetDevice = deviceDao.findDeviceByTenantIdAndName(targetProfile.getTenantId().getId(), provisionRequest.getDeviceName()).orElse(null); |
|||
|
|||
switch (targetProfile.getProvisionType()) { |
|||
case ALLOW_CREATE_NEW_DEVICES: |
|||
if (targetProfile.getProfileData().getProvisionConfiguration().getProvisionDeviceSecret().equals(provisionRequestSecret)) { |
|||
if (targetDevice != null) { |
|||
log.warn("[{}] The device is present and could not be provisioned once more!", targetDevice.getName()); |
|||
notify(targetDevice, provisionRequest, DataConstants.PROVISION_FAILURE, false); |
|||
throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); |
|||
} else { |
|||
return createDevice(provisionRequest, targetProfile); |
|||
} |
|||
} |
|||
break; |
|||
case CHECK_PRE_PROVISIONED_DEVICES: |
|||
if (targetProfile.getProfileData().getProvisionConfiguration().getProvisionDeviceSecret().equals(provisionRequestSecret)) { |
|||
if (targetDevice != null && targetDevice.getDeviceProfileId().equals(targetProfile.getId())) { |
|||
return processProvision(targetDevice, provisionRequest); |
|||
} else { |
|||
log.warn("[{}] Failed to find pre provisioned device!", provisionRequest.getDeviceName()); |
|||
throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
throw new ProvisionFailedException(ProvisionResponseStatus.NOT_FOUND.name()); |
|||
} |
|||
|
|||
private ProvisionResponse processProvision(Device device, ProvisionRequest provisionRequest) { |
|||
try { |
|||
Optional<AttributeKvEntry> provisionState = attributesService.find(device.getTenantId(), device.getId(), |
|||
DataConstants.SERVER_SCOPE, DEVICE_PROVISION_STATE).get(); |
|||
if (provisionState != null && provisionState.isPresent() && !provisionState.get().getValueAsString().equals(PROVISIONED_STATE)) { |
|||
notify(device, provisionRequest, DataConstants.PROVISION_FAILURE, false); |
|||
throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); |
|||
} else { |
|||
saveProvisionStateAttribute(device).get(); |
|||
notify(device, provisionRequest, DataConstants.PROVISION_SUCCESS, true); |
|||
} |
|||
} catch (InterruptedException | ExecutionException e) { |
|||
throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); |
|||
} |
|||
return new ProvisionResponse(deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), device.getId()), ProvisionResponseStatus.SUCCESS); |
|||
} |
|||
|
|||
private ProvisionResponse createDevice(ProvisionRequest provisionRequest, DeviceProfile profile) { |
|||
deviceCreationLock.lock(); |
|||
try { |
|||
return processCreateDevice(provisionRequest, profile); |
|||
} finally { |
|||
deviceCreationLock.unlock(); |
|||
} |
|||
} |
|||
|
|||
private void notify(Device device, ProvisionRequest provisionRequest, String type, boolean success) { |
|||
pushProvisionEventToRuleEngine(provisionRequest, device, type); |
|||
logAction(device.getTenantId(), device.getCustomerId(), device, success, provisionRequest); |
|||
} |
|||
|
|||
private ProvisionResponse processCreateDevice(ProvisionRequest provisionRequest, DeviceProfile profile) { |
|||
Device device = deviceService.findDeviceByTenantIdAndName(profile.getTenantId(), provisionRequest.getDeviceName()); |
|||
try { |
|||
if (device == null) { |
|||
Device savedDevice = deviceService.saveDevice(provisionRequest, profile); |
|||
|
|||
deviceStateService.onDeviceAdded(savedDevice); |
|||
saveProvisionStateAttribute(savedDevice).get(); |
|||
pushDeviceCreatedEventToRuleEngine(savedDevice); |
|||
notify(savedDevice, provisionRequest, DataConstants.PROVISION_SUCCESS, true); |
|||
|
|||
return new ProvisionResponse(getDeviceCredentials(savedDevice), ProvisionResponseStatus.SUCCESS); |
|||
} else { |
|||
log.warn("[{}] The device is already provisioned!", device.getName()); |
|||
notify(device, provisionRequest, DataConstants.PROVISION_FAILURE, false); |
|||
throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); |
|||
} |
|||
} catch (InterruptedException | ExecutionException e) { |
|||
throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); |
|||
} |
|||
} |
|||
|
|||
private ListenableFuture<List<Void>> saveProvisionStateAttribute(Device device) { |
|||
return attributesService.save(device.getTenantId(), device.getId(), DataConstants.SERVER_SCOPE, |
|||
Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry(DEVICE_PROVISION_STATE, PROVISIONED_STATE), |
|||
System.currentTimeMillis()))); |
|||
} |
|||
|
|||
private DeviceCredentials getDeviceCredentials(Device device) { |
|||
return deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), device.getId()); |
|||
} |
|||
|
|||
private void pushProvisionEventToRuleEngine(ProvisionRequest request, Device device, String type) { |
|||
try { |
|||
JsonNode entityNode = JacksonUtil.valueToTree(request); |
|||
TbMsg msg = TbMsg.newMsg(type, device.getId(), createTbMsgMetaData(device), JacksonUtil.toString(entityNode)); |
|||
sendToRuleEngine(device.getTenantId(), msg, null); |
|||
} catch (IllegalArgumentException e) { |
|||
log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), type, e); |
|||
} |
|||
} |
|||
|
|||
private void pushDeviceCreatedEventToRuleEngine(Device device) { |
|||
try { |
|||
ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device); |
|||
TbMsg msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, device.getId(), createTbMsgMetaData(device), JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); |
|||
sendToRuleEngine(device.getTenantId(), msg, null); |
|||
} catch (JsonProcessingException | IllegalArgumentException e) { |
|||
log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), DataConstants.ENTITY_CREATED, e); |
|||
} |
|||
} |
|||
|
|||
protected void sendToRuleEngine(TenantId tenantId, TbMsg tbMsg, TbQueueCallback callback) { |
|||
TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tenantId, tbMsg.getOriginator()); |
|||
TransportProtos.ToRuleEngineMsg msg = TransportProtos.ToRuleEngineMsg.newBuilder().setTbMsg(TbMsg.toByteString(tbMsg)) |
|||
.setTenantIdMSB(tenantId.getId().getMostSignificantBits()) |
|||
.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()).build(); |
|||
ruleEngineMsgProducer.send(tpi, new TbProtoQueueMsg<>(tbMsg.getId(), msg), callback); |
|||
} |
|||
|
|||
private TbMsgMetaData createTbMsgMetaData(Device device) { |
|||
TbMsgMetaData metaData = new TbMsgMetaData(); |
|||
metaData.putValue("tenantId", device.getTenantId().toString()); |
|||
return metaData; |
|||
} |
|||
|
|||
private void logAction(TenantId tenantId, CustomerId customerId, Device device, boolean success, ProvisionRequest provisionRequest) { |
|||
ActionType actionType = success ? ActionType.PROVISION_SUCCESS : ActionType.PROVISION_FAILURE; |
|||
auditLogService.logEntityAction(tenantId, customerId, new UserId(UserId.NULL_UUID), device.getName(), device.getId(), device, actionType, null, provisionRequest); |
|||
} |
|||
} |
|||
@ -0,0 +1,285 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.mqtt.provision; |
|||
|
|||
import com.google.gson.JsonObject; |
|||
import io.netty.handler.codec.mqtt.MqttQoS; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.eclipse.paho.client.mqttv3.MqttCallback; |
|||
import org.eclipse.paho.client.mqttv3.MqttMessage; |
|||
import org.junit.After; |
|||
import org.junit.Assert; |
|||
import org.junit.Test; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.DeviceProfileProvisionType; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.common.msg.EncryptionUtil; |
|||
import org.thingsboard.server.common.transport.util.JsonUtils; |
|||
import org.thingsboard.server.dao.device.DeviceCredentialsService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus; |
|||
import org.thingsboard.server.dao.util.mapping.JacksonUtil; |
|||
import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; |
|||
|
|||
import java.util.concurrent.CountDownLatch; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIntegrationTest { |
|||
|
|||
@Autowired |
|||
DeviceCredentialsService deviceCredentialsService; |
|||
|
|||
@Autowired |
|||
DeviceService deviceService; |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
super.processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningDisabledDevice() throws Exception { |
|||
processTestProvisioningDisabledDevice(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningCheckPreProvisionedDevice() throws Exception { |
|||
processTestProvisioningCheckPreProvisionedDevice(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningCreateNewDeviceWithoutCredentials() throws Exception { |
|||
processTestProvisioningCreateNewDeviceWithoutCredentials(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningCreateNewDeviceWithAccessToken() throws Exception { |
|||
processTestProvisioningCreateNewDeviceWithAccessToken(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningCreateNewDeviceWithCert() throws Exception { |
|||
processTestProvisioningCreateNewDeviceWithCert(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningCreateNewDeviceWithMqttBasic() throws Exception { |
|||
processTestProvisioningCreateNewDeviceWithMqttBasic(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningWithBadKeyDevice() throws Exception { |
|||
processTestProvisioningWithBadKeyDevice(); |
|||
} |
|||
|
|||
|
|||
protected void processTestProvisioningDisabledDevice() throws Exception { |
|||
super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.DISABLED, null, null); |
|||
byte[] result = createMqttClientAndPublish().getPayloadBytes(); |
|||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); |
|||
Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString()); |
|||
Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.get("provisionDeviceStatus").getAsString()); |
|||
} |
|||
|
|||
|
|||
protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception { |
|||
super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); |
|||
byte[] result = createMqttClientAndPublish().getPayloadBytes(); |
|||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); |
|||
|
|||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); |
|||
|
|||
Assert.assertNotNull(createdDevice); |
|||
Assert.assertEquals(createdDevice.getId().toString(), response.get("deviceId").getAsString()); |
|||
|
|||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString()); |
|||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("provisionDeviceStatus").getAsString()); |
|||
} |
|||
|
|||
|
|||
protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { |
|||
super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); |
|||
String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\""; |
|||
byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); |
|||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); |
|||
|
|||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); |
|||
|
|||
Assert.assertNotNull(createdDevice); |
|||
Assert.assertEquals(createdDevice.getId().toString(), response.get("deviceId").getAsString()); |
|||
|
|||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "ACCESS_TOKEN"); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), "test_token"); |
|||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("provisionDeviceStatus").getAsString()); |
|||
} |
|||
|
|||
|
|||
protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception { |
|||
super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); |
|||
String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\""; |
|||
byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); |
|||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); |
|||
|
|||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); |
|||
|
|||
Assert.assertNotNull(createdDevice); |
|||
Assert.assertEquals(createdDevice.getId().toString(), response.get("deviceId").getAsString()); |
|||
|
|||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "X509_CERTIFICATE"); |
|||
|
|||
String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue()); |
|||
String sha3Hash = EncryptionUtil.getSha3Hash(cert); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsValue(), "testHash"); |
|||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("provisionDeviceStatus").getAsString()); |
|||
} |
|||
|
|||
|
|||
protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception { |
|||
super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); |
|||
String requestCredentials = ",\"credentialsType\": \"MQTT_BASIC\",\"clientId\": \"test_clientId\",\"username\": \"test_username\",\"password\": \"test_password\""; |
|||
byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); |
|||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); |
|||
|
|||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); |
|||
|
|||
Assert.assertNotNull(createdDevice); |
|||
Assert.assertEquals(createdDevice.getId().toString(), response.get("deviceId").getAsString()); |
|||
|
|||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "MQTT_BASIC"); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), EncryptionUtil.getSha3Hash("|", "test_clientId", "test_username")); |
|||
|
|||
BasicMqttCredentials mqttCredentials = new BasicMqttCredentials(); |
|||
mqttCredentials.setClientId("test_clientId"); |
|||
mqttCredentials.setUserName("test_username"); |
|||
mqttCredentials.setPassword("test_password"); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsValue(), JacksonUtil.toString(mqttCredentials)); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString()); |
|||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("provisionDeviceStatus").getAsString()); |
|||
} |
|||
|
|||
protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception { |
|||
super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret"); |
|||
byte[] result = createMqttClientAndPublish().getPayloadBytes(); |
|||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); |
|||
Assert.assertEquals(savedDevice.getId().toString(), response.get("deviceId").getAsString()); |
|||
|
|||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId()); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString()); |
|||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("provisionDeviceStatus").getAsString()); |
|||
} |
|||
|
|||
protected void processTestProvisioningWithBadKeyDevice() throws Exception { |
|||
super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret"); |
|||
byte[] result = createMqttClientAndPublish().getPayloadBytes(); |
|||
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); |
|||
Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString()); |
|||
Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.get("provisionDeviceStatus").getAsString()); |
|||
} |
|||
|
|||
protected TestMqttCallback createMqttClientAndPublish() throws Exception { |
|||
return createMqttClientAndPublish(""); |
|||
} |
|||
|
|||
protected TestMqttCallback createMqttClientAndPublish(String deviceCredentials) throws Exception { |
|||
String provisionRequestMsg = createTestProvisionMessage(deviceCredentials); |
|||
MqttAsyncClient client = getMqttAsyncClient("provision"); |
|||
TestMqttCallback onProvisionCallback = getTestMqttCallback(); |
|||
client.setCallback(onProvisionCallback); |
|||
client.subscribe(MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC, MqttQoS.AT_MOST_ONCE.value()); |
|||
Thread.sleep(2000); |
|||
client.publish(MqttTopics.DEVICE_PROVISION_REQUEST_TOPIC, new MqttMessage(provisionRequestMsg.getBytes())); |
|||
onProvisionCallback.getLatch().await(3, TimeUnit.SECONDS); |
|||
return onProvisionCallback; |
|||
} |
|||
|
|||
|
|||
protected TestMqttCallback getTestMqttCallback() { |
|||
CountDownLatch latch = new CountDownLatch(1); |
|||
return new TestMqttCallback(latch); |
|||
} |
|||
|
|||
|
|||
protected static class TestMqttCallback implements MqttCallback { |
|||
|
|||
private final CountDownLatch latch; |
|||
private Integer qoS; |
|||
private byte[] payloadBytes; |
|||
|
|||
TestMqttCallback(CountDownLatch latch) { |
|||
this.latch = latch; |
|||
} |
|||
|
|||
public int getQoS() { |
|||
return qoS; |
|||
} |
|||
|
|||
public byte[] getPayloadBytes() { |
|||
return payloadBytes; |
|||
} |
|||
|
|||
public CountDownLatch getLatch() { |
|||
return latch; |
|||
} |
|||
|
|||
@Override |
|||
public void connectionLost(Throwable throwable) { |
|||
} |
|||
|
|||
@Override |
|||
public void messageArrived(String requestTopic, MqttMessage mqttMessage) throws Exception { |
|||
qoS = mqttMessage.getQos(); |
|||
payloadBytes = mqttMessage.getPayload(); |
|||
latch.countDown(); |
|||
} |
|||
|
|||
@Override |
|||
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { |
|||
|
|||
} |
|||
} |
|||
|
|||
protected String createTestProvisionMessage(String deviceCredentials) { |
|||
return "{\"deviceName\":\"Test Provision device\",\"provisionDeviceKey\":\"testProvisionKey\", \"provisionDeviceSecret\":\"testProvisionSecret\"" + deviceCredentials + "}"; |
|||
} |
|||
} |
|||
@ -0,0 +1,305 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.mqtt.provision; |
|||
|
|||
import io.netty.handler.codec.mqtt.MqttQoS; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.eclipse.paho.client.mqttv3.MqttCallback; |
|||
import org.eclipse.paho.client.mqttv3.MqttMessage; |
|||
import org.junit.After; |
|||
import org.junit.Assert; |
|||
import org.junit.Test; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.DeviceProfileProvisionType; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
|||
import org.thingsboard.server.common.msg.EncryptionUtil; |
|||
import org.thingsboard.server.dao.device.DeviceCredentialsService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus; |
|||
import org.thingsboard.server.dao.util.mapping.JacksonUtil; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.CredentialsDataProto; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.CredentialsType; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceCredentialsMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateBasicMqttCredRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; |
|||
import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; |
|||
|
|||
import java.util.UUID; |
|||
import java.util.concurrent.CountDownLatch; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttIntegrationTest { |
|||
|
|||
@Autowired |
|||
DeviceCredentialsService deviceCredentialsService; |
|||
|
|||
@Autowired |
|||
DeviceService deviceService; |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
super.processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningDisabledDevice() throws Exception { |
|||
processTestProvisioningDisabledDevice(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningCheckPreProvisionedDevice() throws Exception { |
|||
processTestProvisioningCheckPreProvisionedDevice(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningCreateNewDeviceWithoutCredentials() throws Exception { |
|||
processTestProvisioningCreateNewDeviceWithoutCredentials(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningCreateNewDeviceWithAccessToken() throws Exception { |
|||
processTestProvisioningCreateNewDeviceWithAccessToken(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningCreateNewDeviceWithCert() throws Exception { |
|||
processTestProvisioningCreateNewDeviceWithCert(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningCreateNewDeviceWithMqttBasic() throws Exception { |
|||
processTestProvisioningCreateNewDeviceWithMqttBasic(); |
|||
} |
|||
|
|||
@Test |
|||
public void testProvisioningWithBadKeyDevice() throws Exception { |
|||
processTestProvisioningWithBadKeyDevice(); |
|||
} |
|||
|
|||
|
|||
protected void processTestProvisioningDisabledDevice() throws Exception { |
|||
super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.DISABLED, null, null); |
|||
ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); |
|||
Assert.assertNotNull(result); |
|||
Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getProvisionResponseStatus().toString()); |
|||
} |
|||
|
|||
protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception { |
|||
super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); |
|||
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); |
|||
|
|||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); |
|||
|
|||
Assert.assertNotNull(createdDevice); |
|||
Assert.assertEquals(createdDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB())); |
|||
|
|||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getDeviceCredentials().getCredentialsType().toString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId()); |
|||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getProvisionResponseStatus().toString()); |
|||
} |
|||
|
|||
protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { |
|||
super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); |
|||
CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build(); |
|||
|
|||
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayloadBytes()); |
|||
|
|||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); |
|||
|
|||
Assert.assertNotNull(createdDevice); |
|||
Assert.assertEquals(createdDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB())); |
|||
|
|||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getDeviceCredentials().getCredentialsType().toString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.ACCESS_TOKEN); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), "test_token"); |
|||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getProvisionResponseStatus().toString()); |
|||
} |
|||
|
|||
protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception { |
|||
super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); |
|||
CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build(); |
|||
|
|||
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayloadBytes()); |
|||
|
|||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); |
|||
|
|||
Assert.assertNotNull(createdDevice); |
|||
Assert.assertEquals(createdDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB())); |
|||
|
|||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getDeviceCredentials().getCredentialsType().toString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.X509_CERTIFICATE); |
|||
|
|||
String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue()); |
|||
String sha3Hash = EncryptionUtil.getSha3Hash(cert); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsValue(), "testHash"); |
|||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getProvisionResponseStatus().toString()); |
|||
} |
|||
|
|||
protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception { |
|||
super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); |
|||
CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateBasicMqttCredRequestMsg( |
|||
ValidateBasicMqttCredRequestMsg.newBuilder() |
|||
.setClientId("test_clientId") |
|||
.setUserName("test_username") |
|||
.setPassword("test_password") |
|||
.build() |
|||
).build(); |
|||
|
|||
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.MQTT_BASIC, requestCredentials)).getPayloadBytes()); |
|||
|
|||
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); |
|||
|
|||
Assert.assertNotNull(createdDevice); |
|||
Assert.assertEquals(createdDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB())); |
|||
|
|||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getDeviceCredentials().getCredentialsType().toString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.MQTT_BASIC); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), EncryptionUtil.getSha3Hash("|", "test_clientId", "test_username")); |
|||
|
|||
BasicMqttCredentials mqttCredentials = new BasicMqttCredentials(); |
|||
mqttCredentials.setClientId("test_clientId"); |
|||
mqttCredentials.setUserName("test_username"); |
|||
mqttCredentials.setPassword("test_password"); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsValue(), JacksonUtil.toString(mqttCredentials)); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId()); |
|||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getProvisionResponseStatus().toString()); |
|||
} |
|||
|
|||
protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception { |
|||
super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret"); |
|||
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); |
|||
Assert.assertEquals(savedDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB())); |
|||
|
|||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId()); |
|||
|
|||
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getDeviceCredentials().getCredentialsType().toString()); |
|||
Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId()); |
|||
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getProvisionResponseStatus().toString()); |
|||
} |
|||
|
|||
protected void processTestProvisioningWithBadKeyDevice() throws Exception { |
|||
super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret"); |
|||
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); |
|||
Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getProvisionResponseStatus().toString()); |
|||
} |
|||
|
|||
protected TestMqttCallback createMqttClientAndPublish() throws Exception { |
|||
byte[] provisionRequestMsg = createTestProvisionMessage(); |
|||
return createMqttClientAndPublish(provisionRequestMsg); |
|||
} |
|||
|
|||
protected TestMqttCallback createMqttClientAndPublish(byte[] provisionRequestMsg) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient("provision"); |
|||
TestMqttCallback onProvisionCallback = getTestMqttCallback(); |
|||
client.setCallback(onProvisionCallback); |
|||
client.subscribe(MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC, MqttQoS.AT_MOST_ONCE.value()); |
|||
Thread.sleep(2000); |
|||
client.publish(MqttTopics.DEVICE_PROVISION_REQUEST_TOPIC, new MqttMessage(provisionRequestMsg)); |
|||
onProvisionCallback.getLatch().await(3, TimeUnit.SECONDS); |
|||
return onProvisionCallback; |
|||
} |
|||
|
|||
|
|||
protected TestMqttCallback getTestMqttCallback() { |
|||
CountDownLatch latch = new CountDownLatch(1); |
|||
return new TestMqttCallback(latch); |
|||
} |
|||
|
|||
|
|||
protected static class TestMqttCallback implements MqttCallback { |
|||
|
|||
private final CountDownLatch latch; |
|||
private Integer qoS; |
|||
private byte[] payloadBytes; |
|||
|
|||
TestMqttCallback(CountDownLatch latch) { |
|||
this.latch = latch; |
|||
} |
|||
|
|||
public int getQoS() { |
|||
return qoS; |
|||
} |
|||
|
|||
public byte[] getPayloadBytes() { |
|||
return payloadBytes; |
|||
} |
|||
|
|||
public CountDownLatch getLatch() { |
|||
return latch; |
|||
} |
|||
|
|||
@Override |
|||
public void connectionLost(Throwable throwable) { |
|||
} |
|||
|
|||
@Override |
|||
public void messageArrived(String requestTopic, MqttMessage mqttMessage) throws Exception { |
|||
qoS = mqttMessage.getQos(); |
|||
payloadBytes = mqttMessage.getPayload(); |
|||
latch.countDown(); |
|||
} |
|||
|
|||
@Override |
|||
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { |
|||
|
|||
} |
|||
} |
|||
|
|||
protected byte[] createTestsProvisionMessage(CredentialsType credentialsType, CredentialsDataProto credentialsData) throws Exception { |
|||
return ProvisionDeviceRequestMsg.newBuilder() |
|||
.setDeviceName("Test Provision device") |
|||
.setCredentialsType(credentialsType != null ? credentialsType : CredentialsType.ACCESS_TOKEN) |
|||
.setCredentialsDataProto(credentialsData != null ? credentialsData: CredentialsDataProto.newBuilder().build()) |
|||
.setProvisionDeviceCredentialsMsg( |
|||
ProvisionDeviceCredentialsMsg.newBuilder() |
|||
.setProvisionDeviceKey("testProvisionKey") |
|||
.setProvisionDeviceSecret("testProvisionSecret") |
|||
).build() |
|||
.toByteArray(); |
|||
} |
|||
|
|||
|
|||
protected byte[] createTestProvisionMessage() throws Exception { |
|||
return createTestsProvisionMessage(null, null); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.mqtt.provision.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.provision.AbstractMqttProvisionJsonDeviceTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttProvisionDeviceJsonSqlTest extends AbstractMqttProvisionJsonDeviceTest { |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.mqtt.provision.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.provision.AbstractMqttProvisionProtoDeviceTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttProvisionDeviceProtoSqlTest extends AbstractMqttProvisionProtoDeviceTest { |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.dao.device; |
|||
|
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.DeviceProfile; |
|||
import org.thingsboard.server.dao.device.provision.ProvisionFailedException; |
|||
import org.thingsboard.server.dao.device.provision.ProvisionRequest; |
|||
import org.thingsboard.server.dao.device.provision.ProvisionResponse; |
|||
|
|||
public interface DeviceProvisionService { |
|||
|
|||
ProvisionResponse provisionDevice(ProvisionRequest provisionRequest) throws ProvisionFailedException; |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.dao.device.provision; |
|||
|
|||
public class ProvisionFailedException extends RuntimeException { |
|||
public ProvisionFailedException(String errorMsg) { |
|||
super(errorMsg); |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.dao.device.provision; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData; |
|||
import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
public class ProvisionRequest { |
|||
private String deviceName; |
|||
private DeviceCredentialsType credentialsType; |
|||
private ProvisionDeviceCredentialsData credentialsData; |
|||
private ProvisionDeviceProfileCredentials credentials; |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.dao.device.provision; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
|
|||
@Data |
|||
public class ProvisionResponse { |
|||
private final DeviceCredentials deviceCredentials; |
|||
private final ProvisionResponseStatus responseStatus; |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.dao.device.provision; |
|||
|
|||
public enum ProvisionResponseStatus { |
|||
UNKNOWN, |
|||
SUCCESS, |
|||
NOT_FOUND, |
|||
FAILURE |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.common.data; |
|||
|
|||
public enum DeviceProfileProvisionType { |
|||
DISABLED, |
|||
ALLOW_CREATE_NEW_DEVICES, |
|||
CHECK_PRE_PROVISIONED_DEVICES |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.common.data.device.credentials; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class ProvisionDeviceCredentialsData { |
|||
private final String token; |
|||
private final String clientId; |
|||
private final String username; |
|||
private final String password; |
|||
private final String x509CertHash; |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.DeviceProfileProvisionType; |
|||
|
|||
@Data |
|||
public class AllowCreateNewDevicesDeviceProfileProvisionConfiguration implements DeviceProfileProvisionConfiguration { |
|||
|
|||
private final String provisionDeviceSecret; |
|||
|
|||
@Override |
|||
public DeviceProfileProvisionType getType() { |
|||
return DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.DeviceProfileProvisionType; |
|||
|
|||
@Data |
|||
public class CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration implements DeviceProfileProvisionConfiguration { |
|||
|
|||
private final String provisionDeviceSecret; |
|||
|
|||
@Override |
|||
public DeviceProfileProvisionType getType() { |
|||
return DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
import com.fasterxml.jackson.annotation.JsonSubTypes; |
|||
import com.fasterxml.jackson.annotation.JsonTypeInfo; |
|||
import org.thingsboard.server.common.data.DeviceProfileProvisionType; |
|||
|
|||
|
|||
@JsonIgnoreProperties(ignoreUnknown = true) |
|||
@JsonTypeInfo( |
|||
use = JsonTypeInfo.Id.NAME, |
|||
include = JsonTypeInfo.As.PROPERTY, |
|||
property = "type") |
|||
@JsonSubTypes({ |
|||
@JsonSubTypes.Type(value = DisabledDeviceProfileProvisionConfiguration.class, name = "DISABLED"), |
|||
@JsonSubTypes.Type(value = AllowCreateNewDevicesDeviceProfileProvisionConfiguration.class, name = "ALLOW_CREATE_NEW_DEVICES"), |
|||
@JsonSubTypes.Type(value = CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration.class, name = "CHECK_PRE_PROVISIONED_DEVICES")}) |
|||
public interface DeviceProfileProvisionConfiguration { |
|||
|
|||
String getProvisionDeviceSecret(); |
|||
|
|||
@JsonIgnore |
|||
DeviceProfileProvisionType getType(); |
|||
|
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.DeviceProfileProvisionType; |
|||
|
|||
@Data |
|||
public class DisabledDeviceProfileProvisionConfiguration implements DeviceProfileProvisionConfiguration { |
|||
|
|||
private final String provisionDeviceSecret; |
|||
|
|||
@Override |
|||
public DeviceProfileProvisionType getType() { |
|||
return DeviceProfileProvisionType.DISABLED; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed 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 org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class ProvisionDeviceProfileCredentials { |
|||
private final String provisionDeviceKey; |
|||
private final String provisionDeviceSecret; |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2020 The Thingsboard Authors |
|||
|
|||
Licensed 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. |
|||
|
|||
--> |
|||
<div [formGroup]="provisionConfigurationFormGroup"> |
|||
<mat-form-field class="mat-block"> |
|||
<mat-label translate>device-profile.provision-strategy</mat-label> |
|||
<mat-select formControlName="type" required> |
|||
<mat-option *ngFor="let type of deviceProvisionTypes" [value]="type"> |
|||
{{deviceProvisionTypeTranslateMap.get(type) | translate}} |
|||
</mat-option> |
|||
</mat-select> |
|||
<mat-error *ngIf="provisionConfigurationFormGroup.get('type').hasError('required')"> |
|||
{{ 'device-profile.provision-strategy-required' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
<section *ngIf="provisionConfigurationFormGroup.get('type').value !== deviceProvisionType.DISABLED" fxLayoutGap.gt-xs="8px" fxLayout="row" fxLayout.xs="column"> |
|||
<mat-form-field fxFlex class="mat-block"> |
|||
<mat-label translate>device-profile.provision-device-key</mat-label> |
|||
<input matInput formControlName="provisionDeviceKey" required/> |
|||
<mat-error *ngIf="provisionConfigurationFormGroup.get('provisionDeviceKey').hasError('required')"> |
|||
{{ 'device-profile.provision-device-key-required' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
<mat-form-field fxFlex class="mat-block"> |
|||
<mat-label translate>device-profile.provision-device-secret</mat-label> |
|||
<input matInput formControlName="provisionDeviceSecret" required/> |
|||
<mat-error *ngIf="provisionConfigurationFormGroup.get('provisionDeviceSecret').hasError('required')"> |
|||
{{ 'device-profile.provision-device-secret-required' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
</section> |
|||
</div> |
|||
@ -0,0 +1,140 @@ |
|||
///
|
|||
/// Copyright © 2016-2020 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed 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.
|
|||
///
|
|||
|
|||
import { Component, forwardRef, Input, OnInit } from "@angular/core"; |
|||
import { |
|||
ControlValueAccessor, |
|||
FormBuilder, |
|||
FormControl, |
|||
FormGroup, |
|||
NG_VALIDATORS, |
|||
NG_VALUE_ACCESSOR, |
|||
ValidationErrors, |
|||
Validator, |
|||
Validators |
|||
} from "@angular/forms"; |
|||
import { coerceBooleanProperty } from "@angular/cdk/coercion"; |
|||
import { |
|||
DeviceProvisionConfiguration, |
|||
DeviceProvisionType, |
|||
deviceProvisionTypeTranslationMap |
|||
} from "@shared/models/device.models"; |
|||
import { isDefinedAndNotNull } from "@core/utils"; |
|||
|
|||
@Component({ |
|||
selector: 'tb-device-profile-provision-configuration', |
|||
templateUrl: './device-profile-provision-configuration.component.html', |
|||
styleUrls: [], |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => DeviceProfileProvisionConfigurationComponent), |
|||
multi: true |
|||
}, |
|||
{ |
|||
provide: NG_VALIDATORS, |
|||
useExisting: forwardRef(() => DeviceProfileProvisionConfigurationComponent), |
|||
multi: true, |
|||
} |
|||
] |
|||
}) |
|||
export class DeviceProfileProvisionConfigurationComponent implements ControlValueAccessor, OnInit, Validator { |
|||
|
|||
provisionConfigurationFormGroup: FormGroup; |
|||
|
|||
deviceProvisionType = DeviceProvisionType; |
|||
deviceProvisionTypes = Object.keys(DeviceProvisionType); |
|||
deviceProvisionTypeTranslateMap = deviceProvisionTypeTranslationMap; |
|||
|
|||
private requiredValue: boolean; |
|||
get required(): boolean { |
|||
return this.requiredValue; |
|||
} |
|||
@Input() |
|||
set required(value: boolean) { |
|||
this.requiredValue = coerceBooleanProperty(value); |
|||
} |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
private propagateChange = (v: any) => { }; |
|||
|
|||
constructor(private fb: FormBuilder) { |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
this.provisionConfigurationFormGroup = this.fb.group({ |
|||
type: [DeviceProvisionType.DISABLED, Validators.required], |
|||
provisionDeviceSecret: [{value: null, disabled: true}, Validators.required], |
|||
provisionDeviceKey: [{value: null, disabled: true}, Validators.required] |
|||
}); |
|||
this.provisionConfigurationFormGroup.get('type').valueChanges.subscribe((type) => { |
|||
if (type === DeviceProvisionType.DISABLED) { |
|||
this.provisionConfigurationFormGroup.get('provisionDeviceSecret').disable({emitEvent: false}); |
|||
this.provisionConfigurationFormGroup.get('provisionDeviceSecret').patchValue(null,{emitEvent: false}); |
|||
this.provisionConfigurationFormGroup.get('provisionDeviceKey').disable({emitEvent: false}); |
|||
this.provisionConfigurationFormGroup.get('provisionDeviceKey').patchValue(null); |
|||
} else { |
|||
this.provisionConfigurationFormGroup.get('provisionDeviceSecret').enable({emitEvent: false}); |
|||
this.provisionConfigurationFormGroup.get('provisionDeviceKey').enable({emitEvent: false}); |
|||
} |
|||
}); |
|||
this.provisionConfigurationFormGroup.valueChanges.subscribe(() => { |
|||
this.updateModel(); |
|||
}); |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
writeValue(value: DeviceProvisionConfiguration | null): void { |
|||
if (isDefinedAndNotNull(value)){ |
|||
this.provisionConfigurationFormGroup.patchValue(value, {emitEvent: false}); |
|||
} else { |
|||
this.provisionConfigurationFormGroup.patchValue({type: DeviceProvisionType.DISABLED}); |
|||
} |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean){ |
|||
this.disabled = isDisabled; |
|||
if (this.disabled){ |
|||
this.provisionConfigurationFormGroup.disable(); |
|||
} else { |
|||
this.provisionConfigurationFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
validate(c: FormControl): ValidationErrors | null { |
|||
return (this.provisionConfigurationFormGroup.valid) ? null : { |
|||
provisionConfiguration: { |
|||
valid: false, |
|||
}, |
|||
}; |
|||
} |
|||
|
|||
private updateModel(): void { |
|||
let deviceProvisionConfiguration: DeviceProvisionConfiguration = null; |
|||
if (this.provisionConfigurationFormGroup.valid) { |
|||
deviceProvisionConfiguration = this.provisionConfigurationFormGroup.getRawValue(); |
|||
} |
|||
this.propagateChange(deviceProvisionConfiguration); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue