From 3364b36000c16dd7ec50628b98a483402a37cb60 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 2 Apr 2026 13:34:26 +0300 Subject: [PATCH] fix(iot-hub): use DeviceConnectivityService for transport variables The admin settings endpoint requires SYS_ADMIN authority but the device install wizard runs as TENANT_ADMIN. Fix: add getConnectivityInfo(baseUrl) to DeviceConnectivityService which resolves host/port with baseUrl fallback (reusing existing getHost/getPort logic). Expose via new TENANT_ADMIN endpoint GET /api/iot-hub/connectivity. Remove AdminService dependency from the dialog component. --- .../server/controller/IotHubController.java | 12 ++++++++++++ .../dao/device/DeviceConnectivityService.java | 2 ++ .../device/DeviceConnectivityServiceImpl.java | 18 ++++++++++++++++++ .../src/app/core/http/iot-hub-api.service.ts | 8 ++++++++ .../device-install-dialog.component.ts | 8 +++----- 5 files changed, 43 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/IotHubController.java b/application/src/main/java/org/thingsboard/server/controller/IotHubController.java index 06de253471..abe05bc2cf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/IotHubController.java +++ b/application/src/main/java/org/thingsboard/server/controller/IotHubController.java @@ -40,8 +40,10 @@ import org.thingsboard.server.common.data.page.PageLink; import java.util.List; import java.util.UUID; import org.thingsboard.server.common.data.id.IotHubInstalledItemId; +import org.thingsboard.server.dao.device.DeviceConnectivityService; import org.thingsboard.server.dao.iot_hub.IotHubInstalledItemService; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.security.system.SystemSecurityService; import org.thingsboard.server.service.iot_hub.InstallItemVersionResult; import org.thingsboard.server.service.iot_hub.UpdateItemVersionResult; import org.thingsboard.server.service.iot_hub.IotHubService; @@ -56,6 +58,8 @@ public class IotHubController extends BaseController { private final IotHubService iotHubService; private final IotHubInstalledItemService iotHubInstalledItemService; + private final DeviceConnectivityService deviceConnectivityService; + private final SystemSecurityService systemSecurityService; @PreAuthorize("hasAuthority('TENANT_ADMIN')") @PostMapping("/versions/{versionId}/install") @@ -119,4 +123,12 @@ public class IotHubController extends BaseController { public void deleteInstalledItem(@PathVariable UUID installedItemId) throws ThingsboardException { iotHubService.deleteInstalledItem(getCurrentUser(), new IotHubInstalledItemId(installedItemId)); } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @GetMapping("/connectivity") + @ResponseBody + public JsonNode getConnectivitySettings(HttpServletRequest request) throws Exception { + String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request); + return deviceConnectivityService.getConnectivityInfo(baseUrl); + } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java index 36f6fe0feb..d452b7ddd3 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java @@ -25,6 +25,8 @@ public interface DeviceConnectivityService { JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException; + JsonNode getConnectivityInfo(String baseUrl) throws URISyntaxException; + Resource getPemCertFile(String protocol); Resource createGatewayDockerComposeFile(String baseUrl, Device device) throws URISyntaxException; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java index 89cb538c28..01c3fa3d34 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java @@ -48,6 +48,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Base64; import java.util.List; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -176,6 +177,23 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService return info != null && info.isEnabled(); } + @Override + public JsonNode getConnectivityInfo(String baseUrl) throws URISyntaxException { + String[] protocols = {HTTP, HTTPS, MQTT, MQTTS, COAP, COAPS}; + Map result = new LinkedHashMap<>(); + for (String protocol : protocols) { + DeviceConnectivityInfo info = getConnectivity(protocol); + if (info != null && info.isEnabled()) { + DeviceConnectivityInfo resolved = new DeviceConnectivityInfo(); + resolved.setEnabled(true); + resolved.setHost(getHost(baseUrl, info, protocol)); + resolved.setPort(getPort(info)); + result.put(protocol, resolved); + } + } + return JacksonUtil.valueToTree(result); + } + private Resource getCert(String path) { if (StringUtils.isBlank(path) || !ResourceUtils.resourceExists(this, path)) { return null; diff --git a/ui-ngx/src/app/core/http/iot-hub-api.service.ts b/ui-ngx/src/app/core/http/iot-hub-api.service.ts index bce32a4cd8..c63e03405e 100644 --- a/ui-ngx/src/app/core/http/iot-hub-api.service.ts +++ b/ui-ngx/src/app/core/http/iot-hub-api.service.ts @@ -27,6 +27,7 @@ import { InterceptorHttpParams } from '@core/interceptors/interceptor-http-param import { InterceptorConfig } from '@core/interceptors/interceptor-config'; import { AppState } from '@core/core.state'; import { getCurrentAuthState } from '@core/auth/auth.selectors'; +import { DeviceConnectivitySettings } from '@shared/models/settings.models'; import { environment as env } from '@env/environment'; export function tbVersionToInt(version: string): number { @@ -112,6 +113,13 @@ export class IotHubApiService { ); } + public getConnectivitySettings(config?: IotHubRequestConfig): Observable { + return this.http.get( + `/api/iot-hub/connectivity`, + { params: this.buildParams(config) } + ); + } + public registerDeviceInstall( versionId: string, descriptor: { type?: string; createdEntityIds: { entityType: string; id: string }[]; dashboardId?: { entityType: string; id: string } }, diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.ts b/ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.ts index 66d5cdff78..bcf03100f7 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.ts @@ -30,8 +30,6 @@ import { DeviceProfileService } from '@core/http/device-profile.service'; import { DeviceService } from '@core/http/device.service'; import { DashboardService } from '@core/http/dashboard.service'; import { RuleChainService } from '@core/http/rule-chain.service'; -import { AdminService } from '@core/http/admin.service'; -import { DeviceConnectivitySettings } from '@shared/models/settings.models'; import { connectivityTypeTranslations, DeviceInstallStep, @@ -141,9 +139,9 @@ export class TbDeviceInstallDialogComponent extends DialogComponent('connectivity')); - if (settings?.jsonValue) { - for (const [protocol, info] of Object.entries(settings.jsonValue)) { + const connectivity = await firstValueFrom(this.iotHubApiService.getConnectivitySettings({ ignoreErrors: true })); + if (connectivity) { + for (const [protocol, info] of Object.entries(connectivity)) { if (info) { this.transportVars[`${protocol}.host`] = info.host || ''; this.transportVars[`${protocol}.port`] = String(info.port || '');