diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java index d4bfe9c625..33b2af55fe 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java @@ -37,7 +37,6 @@ 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.data.security.DeviceCredentialsType; -import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.ServiceType; @@ -46,8 +45,6 @@ import org.thingsboard.server.common.transport.util.SslUtil; 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.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceProvisionService; import org.thingsboard.server.dao.device.DeviceService; @@ -63,12 +60,13 @@ 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.regex.Matcher; +import java.util.regex.Pattern; @Service @@ -102,6 +100,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { @Override public ProvisionResponse provisionDevice(ProvisionRequest provisionRequest) { + fetchAndApplyDeviceNameForX509ProvisionRequestWithRegEx(provisionRequest); String provisionRequestKey = provisionRequest.getCredentials().getProvisionDeviceKey(); String provisionRequestSecret = provisionRequest.getCredentials().getProvisionDeviceSecret(); if (!StringUtils.isEmpty(provisionRequest.getDeviceName())) { @@ -160,7 +159,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { } else if (x509Configuration.isAllowCreateNewDevicesByX509Certificate()) { return createDevice(provisionRequest, targetProfile); } else { - log.info("Device doesn't exist and cannot be created due incorrect configuration for X509CertificateChainProvisionConfiguration"); + log.warn("Device with name {} doesn't exist and cannot be created due incorrect configuration for X509CertificateChainProvisionConfiguration", provisionRequest.getDeviceName()); throw new ProvisionFailedException(ProvisionResponseStatus.NOT_FOUND.name()); } } @@ -273,4 +272,34 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { 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); } + + private void fetchAndApplyDeviceNameForX509ProvisionRequestWithRegEx(ProvisionRequest provisionRequest) { + DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileByProvisionDeviceKey(provisionRequest.getCredentials().getProvisionDeviceKey()); + X509CertificateChainProvisionConfiguration configuration; + if (deviceProfile.getProfileData().getProvisionConfiguration() instanceof X509CertificateChainProvisionConfiguration) { + configuration = (X509CertificateChainProvisionConfiguration) deviceProfile.getProfileData().getProvisionConfiguration(); + String certificateValue = provisionRequest.getCredentialsData().getX509CertHash(); + String certificateRegEx = configuration.getCertificateRegExPattern(); + String deviceName = extractDeviceNameFromCertificateCNByRegEx(certificateValue, certificateRegEx); + if (deviceName == null) { + log.warn("Device name cannot be extracted using regex [{}] for certificate [{}]",certificateRegEx, certificateValue); + throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); + } + provisionRequest.setDeviceName(deviceName); + } + } + + private String extractDeviceNameFromCertificateCNByRegEx(String x509Value, String regex) { + try { + String commonName = SslUtil.parseCommonName(SslUtil.readCertFile(x509Value)); + log.trace("Extract CN [{}] by regex pattern [{}]", commonName, regex); + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(commonName); + if (matcher.find()) { + return matcher.group(0); + } + return null; + } catch (Exception ignored) {} + return null; + } } diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index dada1985f3..031564aecf 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -47,9 +47,7 @@ import org.thingsboard.server.common.data.device.data.CoapDeviceTransportConfigu import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration; import org.thingsboard.server.common.data.device.data.PowerMode; import org.thingsboard.server.common.data.device.data.PowerSavingConfiguration; -import org.thingsboard.server.common.data.device.profile.DeviceProfileProvisionConfiguration; import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials; -import org.thingsboard.server.common.data.device.profile.X509CertificateChainProvisionConfiguration; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -67,7 +65,6 @@ import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceProvisionService; @@ -118,6 +115,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static org.thingsboard.server.common.data.DeviceProfileProvisionType.X509_CERTIFICATE_CHAIN; import static org.thingsboard.server.service.transport.BasicCredentialsValidationResult.PASSWORD_MISMATCH; import static org.thingsboard.server.service.transport.BasicCredentialsValidationResult.VALID; @@ -247,13 +245,17 @@ public class DefaultTransportApiService implements TransportApiService { return getDeviceInfo(credentials); } DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileByProvisionDeviceKey(certificateHash); - if (deviceProfile != null) { + if (deviceProfile != null && deviceProfile.getProvisionType() == X509_CERTIFICATE_CHAIN) { String updatedDeviceProvisionSecret = chain.get(0); ProvisionRequest provisionRequest = createProvisionRequest(deviceProfile, updatedDeviceProvisionSecret); - ProvisionResponse provisionResponse = deviceProvisionService.provisionDevice(provisionRequest); - if (provisionResponse.getResponseStatus().equals(ProvisionResponseStatus.SUCCESS)) { + ProvisionResponse provisionResponse = provisionDeviceRequestAndGetResponse(provisionRequest); + if (provisionResponse != null && provisionResponse.getResponseStatus().equals(ProvisionResponseStatus.SUCCESS)) { return getDeviceInfo(provisionResponse.getDeviceCredentials()); + } else { + return getEmptyTransportApiResponseFuture(); } + } else if (deviceProfile != null) { + log.warn("[{}] Device Profile provision configuration mismatched: expected {}, actual {}", deviceProfile.getName(), X509_CERTIFICATE_CHAIN, deviceProfile.getProvisionType()); } } return getEmptyTransportApiResponseFuture(); @@ -700,44 +702,21 @@ public class DefaultTransportApiService implements TransportApiService { } private ProvisionRequest createProvisionRequest(DeviceProfile deviceProfile, String certificateValue) { - String deviceName = getDeviceName(deviceProfile, certificateValue); - ProvisionDeviceProfileCredentials provisionDeviceProfileCredentials = new ProvisionDeviceProfileCredentials( deviceProfile.getProvisionDeviceKey(), deviceProfile.getProfileData().getProvisionConfiguration().getProvisionDeviceSecret() ); ProvisionDeviceCredentialsData provisionDeviceCredentialsData = new ProvisionDeviceCredentialsData(null, null, null, null, certificateValue); - return new ProvisionRequest(deviceName, DeviceCredentialsType.X509_CERTIFICATE, provisionDeviceCredentialsData, provisionDeviceProfileCredentials); + return new ProvisionRequest(null, DeviceCredentialsType.X509_CERTIFICATE, provisionDeviceCredentialsData, provisionDeviceProfileCredentials); } - - private String getDeviceName(DeviceProfile deviceProfile, String certificateValue) { - X509CertificateChainProvisionConfiguration configuration = new X509CertificateChainProvisionConfiguration(); - String deviceName = null; - if (deviceProfile.getProfileData().getProvisionConfiguration() instanceof X509CertificateChainProvisionConfiguration) { - configuration = (X509CertificateChainProvisionConfiguration) deviceProfile.getProfileData().getProvisionConfiguration(); - deviceName = extractDeviceNameFromCertificateCNByRegEx(certificateValue, configuration.getCertificateRegExPattern()); - if (deviceName == null) { - log.warn("Cannot extract device name from device's CN using regex [{}]", configuration.getCertificateRegExPattern()); - } - } else { - log.warn("Device Profile configuration: expected [{}], actual [{}]", configuration.getType(), deviceProfile.getProvisionType()); - } - return deviceName; - } - - private String extractDeviceNameFromCertificateCNByRegEx(String x509Value, String regex) { + private ProvisionResponse provisionDeviceRequestAndGetResponse(ProvisionRequest provisionRequest) { + ProvisionResponse provisionResponse = null; try { - String commonName = SslUtil.parseCommonName(SslUtil.readCertFile(x509Value)); - log.trace("Extract CN [{}] by regex pattern [{}]", commonName, regex); - Pattern pattern = Pattern.compile(regex); - Matcher matcher = pattern.matcher(commonName); - if (matcher.find()) { - return matcher.group(0); - } - } catch (Exception ignored) {} - return null; + provisionResponse = deviceProvisionService.provisionDevice(provisionRequest); + } catch (ProvisionFailedException ignored) {} + return provisionResponse; } private List convertX509CertificateChainToList(String certificateChain) {