diff --git a/application/src/main/data/upgrade/3.6.3/schema_update.sql b/application/src/main/data/upgrade/3.6.3/schema_update.sql index e2d454353e..64c0459cd2 100644 --- a/application/src/main/data/upgrade/3.6.3/schema_update.sql +++ b/application/src/main/data/upgrade/3.6.3/schema_update.sql @@ -14,7 +14,6 @@ -- limitations under the License. -- - -- create new attribute_kv table schema DO $$ @@ -105,4 +104,11 @@ EXCEPTION ROLLBACK; RAISE EXCEPTION 'Error during COPY: %', SQLERRM; END -$$; \ No newline at end of file +$$; + +-- OAUTH2 PARAMS ALTER TABLE START + +ALTER TABLE oauth2_params + ADD COLUMN IF NOT EXISTS edge_enabled boolean DEFAULT false; + +-- OAUTH2 PARAMS ALTER TABLE END diff --git a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java index eede4a3afc..4d1fb8a12a 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java @@ -42,6 +42,7 @@ import org.thingsboard.server.service.edge.rpc.processor.device.DeviceEdgeProces import org.thingsboard.server.service.edge.rpc.processor.device.profile.DeviceProfileEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.edge.EdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewEdgeProcessor; +import org.thingsboard.server.service.edge.rpc.processor.oauth2.OAuth2EdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.ota.OtaPackageEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.queue.QueueEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessor; @@ -126,6 +127,9 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { @Autowired private ResourceEdgeProcessor resourceEdgeProcessor; + @Autowired + private OAuth2EdgeProcessor oAuth2EdgeProcessor; + @Autowired protected ApplicationEventPublisher eventPublisher; @@ -231,6 +235,9 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { case TB_RESOURCE: resourceEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; + case OAUTH2: + oAuth2EdgeProcessor.processOAuth2Notification(tenantId, edgeNotificationMsg); + break; default: log.warn("[{}] Edge event type [{}] is not designed to be pushed to edge", tenantId, type); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java index f5b769e568..5ef8819df0 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java @@ -32,6 +32,7 @@ import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.entityview.EntityViewService; +import org.thingsboard.server.dao.oauth2.OAuth2Service; import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.resource.ResourceService; @@ -61,6 +62,7 @@ import org.thingsboard.server.service.edge.rpc.processor.device.profile.DevicePr import org.thingsboard.server.service.edge.rpc.processor.edge.EdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorFactory; +import org.thingsboard.server.service.edge.rpc.processor.oauth2.OAuth2EdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.ota.OtaPackageEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.queue.QueueEdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessor; @@ -151,6 +153,9 @@ public class EdgeContextComponent { @Autowired private ResourceService resourceService; + @Autowired + private OAuth2Service oAuth2Service; + @Autowired private RateLimitService rateLimitService; @@ -220,6 +225,9 @@ public class EdgeContextComponent { @Autowired private ResourceEdgeProcessor resourceEdgeProcessor; + @Autowired + private OAuth2EdgeProcessor oAuth2EdgeProcessor; + @Autowired private EdgeMsgConstructor edgeMsgConstructor; diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java index e54adb05fa..d975217e1f 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java @@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.common.data.oauth2.OAuth2Info; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rule.RuleChain; @@ -159,43 +160,41 @@ public class EdgeEventSourcingListener { private boolean isValidSaveEntityEventForEdgeProcessing(SaveEntityEvent event) { Object entity = event.getEntity(); Object oldEntity = event.getOldEntity(); - switch (event.getEntityId().getEntityType()) { - case RULE_CHAIN: - if (entity instanceof RuleChain) { - RuleChain ruleChain = (RuleChain) entity; - return RuleChainType.EDGE.equals(ruleChain.getType()); - } - break; - case USER: - if (entity instanceof User) { - User user = (User) entity; - if (Authority.SYS_ADMIN.equals(user.getAuthority())) { + if (event.getEntityId() != null) { + switch (event.getEntityId().getEntityType()) { + case RULE_CHAIN: + if (entity instanceof RuleChain ruleChain) { + return RuleChainType.EDGE.equals(ruleChain.getType()); + } + break; + case USER: + if (entity instanceof User user) { + if (Authority.SYS_ADMIN.equals(user.getAuthority())) { + return false; + } + if (oldEntity != null) { + User oldUser = (User) oldEntity; + cleanUpUserAdditionalInfo(oldUser); + cleanUpUserAdditionalInfo(user); + return !user.equals(oldUser); + } + } + break; + case OTA_PACKAGE: + if (entity instanceof OtaPackageInfo otaPackageInfo) { + return otaPackageInfo.hasUrl() || otaPackageInfo.isHasData(); + } + break; + case ALARM: + if (entity instanceof AlarmApiCallResult || entity instanceof Alarm) { return false; } - if (oldEntity != null) { - User oldUser = (User) oldEntity; - cleanUpUserAdditionalInfo(oldUser); - cleanUpUserAdditionalInfo(user); - return !user.equals(oldUser); - } - } - break; - case OTA_PACKAGE: - if (entity instanceof OtaPackageInfo) { - OtaPackageInfo otaPackageInfo = (OtaPackageInfo) entity; - return otaPackageInfo.hasUrl() || otaPackageInfo.isHasData(); - } - break; - case ALARM: - if (entity instanceof AlarmApiCallResult || entity instanceof Alarm) { + break; + case TENANT: + return !event.getCreated(); + case API_USAGE_STATE, EDGE: return false; - } - break; - case TENANT: - return !event.getCreated(); - case API_USAGE_STATE: - case EDGE: - return false; + } } // Default: If the entity doesn't match any of the conditions, consider it as valid. return true; @@ -206,8 +205,7 @@ public class EdgeEventSourcingListener { if (user.getAdditionalInfo() instanceof NullNode) { user.setAdditionalInfo(null); } - if (user.getAdditionalInfo() instanceof ObjectNode) { - ObjectNode additionalInfo = ((ObjectNode) user.getAdditionalInfo()); + if (user.getAdditionalInfo() instanceof ObjectNode additionalInfo) { additionalInfo.remove(UserServiceImpl.FAILED_LOGIN_ATTEMPTS); additionalInfo.remove(UserServiceImpl.LAST_LOGIN_TS); if (additionalInfo.isEmpty()) { @@ -221,6 +219,8 @@ public class EdgeEventSourcingListener { private EdgeEventType getEdgeEventTypeForEntityEvent(Object entity) { if (entity instanceof AlarmComment) { return EdgeEventType.ALARM_COMMENT; + } else if (entity instanceof OAuth2Info) { + return EdgeEventType.OAUTH2; } return null; } @@ -228,6 +228,8 @@ public class EdgeEventSourcingListener { private String getBodyMsgForEntityEvent(Object entity) { if (entity instanceof AlarmComment) { return JacksonUtil.toString(entity); + } else if (entity instanceof OAuth2Info) { + return JacksonUtil.toString(entity); } return null; } @@ -238,4 +240,5 @@ public class EdgeEventSourcingListener { } return isCreated ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED; } + } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index a73d3a20ff..1453f1a85c 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -705,6 +705,8 @@ public final class EdgeGrpcSession implements Closeable { return ctx.getTenantEdgeProcessor().convertTenantEventToDownlink(edgeEvent, this.edgeVersion); case TENANT_PROFILE: return ctx.getTenantProfileEdgeProcessor().convertTenantProfileEventToDownlink(edgeEvent, this.edgeVersion); + case OAUTH2: + return ctx.getOAuth2EdgeProcessor().convertOAuth2EventToDownlink(edgeEvent); default: log.warn("[{}] Unsupported edge event type [{}]", this.tenantId, edgeEvent); return null; diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java index 8583e8725e..5f7ffc08e3 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java @@ -30,6 +30,7 @@ import org.thingsboard.server.service.edge.rpc.fetch.DeviceProfilesEdgeEventFetc import org.thingsboard.server.service.edge.rpc.fetch.DevicesEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.EdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.EntityViewsEdgeEventFetcher; +import org.thingsboard.server.service.edge.rpc.fetch.OAuth2EdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.OtaPackagesEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.QueuesEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.RuleChainsEdgeEventFetcher; @@ -79,6 +80,7 @@ public class EdgeSyncCursor { fetchers.add(new TenantWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService())); fetchers.add(new OtaPackagesEdgeEventFetcher(ctx.getOtaPackageService())); fetchers.add(new TenantResourcesEdgeEventFetcher(ctx.getResourceService())); + fetchers.add(new OAuth2EdgeEventFetcher(ctx.getOAuth2Service())); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/oauth2/OAuth2MsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/oauth2/OAuth2MsgConstructor.java new file mode 100644 index 0000000000..c628b042a2 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/oauth2/OAuth2MsgConstructor.java @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2024 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.edge.rpc.constructor.oauth2; + +import org.springframework.stereotype.Component; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.oauth2.OAuth2Info; +import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg; +import org.thingsboard.server.queue.util.TbCoreComponent; + +@Component +@TbCoreComponent +public class OAuth2MsgConstructor { + + public OAuth2UpdateMsg constructOAuth2UpdateMsg(OAuth2Info oAuth2Info) { + return OAuth2UpdateMsg.newBuilder().setEntity(JacksonUtil.toString(oAuth2Info)).build(); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/CustomerEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/CustomerEdgeEventFetcher.java index 57596a76de..ff34e618bc 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/CustomerEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/CustomerEdgeEventFetcher.java @@ -46,7 +46,7 @@ public class CustomerEdgeEventFetcher implements EdgeEventFetcher { List result = new ArrayList<>(); result.add(EdgeUtils.constructEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, customerId, null)); - // @voba - returns PageData object to be in sync with other fetchers + // returns PageData object to be in sync with other fetchers return new PageData<>(result, 1, result.size(), false); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/OAuth2EdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/OAuth2EdgeEventFetcher.java new file mode 100644 index 0000000000..4412f91183 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/OAuth2EdgeEventFetcher.java @@ -0,0 +1,56 @@ +/** + * Copyright © 2016-2024 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.edge.rpc.fetch; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.EdgeUtils; +import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.edge.EdgeEvent; +import org.thingsboard.server.common.data.edge.EdgeEventActionType; +import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.oauth2.OAuth2Info; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.oauth2.OAuth2Service; + +import java.util.ArrayList; +import java.util.List; + +@AllArgsConstructor +@Slf4j +public class OAuth2EdgeEventFetcher implements EdgeEventFetcher { + + private final OAuth2Service oAuth2Service; + + @Override + public PageLink getPageLink(int pageSize) { + return null; + } + + @Override + public PageData fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) { + List result = new ArrayList<>(); + OAuth2Info oAuth2Info = oAuth2Service.findOAuth2Info(); + result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.OAUTH2, + EdgeEventActionType.ADDED, null, JacksonUtil.valueToTree(oAuth2Info))); + // returns PageData object to be in sync with other fetchers + return new PageData<>(result, 1, result.size(), false); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java index cd3eea4bef..cc86826d41 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java @@ -51,9 +51,8 @@ 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.msg.TbMsgType; -import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.page.PageDataIterableByTenantIdEntityId; -import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rule.RuleChain; @@ -75,6 +74,7 @@ import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeSynchronizationManager; import org.thingsboard.server.dao.entityview.EntityViewService; +import org.thingsboard.server.dao.oauth2.OAuth2Service; import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; @@ -101,6 +101,7 @@ import org.thingsboard.server.service.edge.rpc.constructor.dashboard.DashboardMs import org.thingsboard.server.service.edge.rpc.constructor.device.DeviceMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.edge.EdgeMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorFactory; +import org.thingsboard.server.service.edge.rpc.constructor.oauth2.OAuth2MsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.queue.QueueMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.relation.RelationMsgConstructorFactory; @@ -226,6 +227,9 @@ public abstract class BaseEdgeProcessor { @Autowired protected ResourceService resourceService; + @Autowired + protected OAuth2Service oAuth2Service; + @Autowired @Lazy protected TbQueueProducerProvider producerProvider; @@ -257,6 +261,9 @@ public abstract class BaseEdgeProcessor { @Autowired protected EntityDataMsgConstructor entityDataMsgConstructor; + @Autowired + protected OAuth2MsgConstructor oAuth2MsgConstructor; + @Autowired protected RuleChainMsgConstructorFactory ruleChainMsgConstructorFactory; @@ -392,18 +399,13 @@ public abstract class BaseEdgeProcessor { protected ListenableFuture processActionForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId, - EdgeId sourceEdgeId) { + JsonNode body, EdgeId sourceEdgeId) { List> futures = new ArrayList<>(); if (TenantId.SYS_TENANT_ID.equals(tenantId)) { - PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); - PageData tenantsIds; - do { - tenantsIds = tenantService.findTenantsIds(pageLink); - for (TenantId tenantId1 : tenantsIds.getData()) { - futures.addAll(processActionForAllEdgesByTenantId(tenantId1, type, actionType, entityId, null, sourceEdgeId)); - } - pageLink = pageLink.nextPageLink(); - } while (tenantsIds.hasNext()); + PageDataIterable tenantIds = new PageDataIterable<>(link -> tenantService.findTenantsIds(link), 1024); + for (TenantId tenantId1 : tenantIds) { + futures.addAll(processActionForAllEdgesByTenantId(tenantId1, type, actionType, entityId, body, sourceEdgeId)); + } } else { futures = processActionForAllEdgesByTenantId(tenantId, type, actionType, entityId, null, sourceEdgeId); } @@ -416,22 +418,13 @@ public abstract class BaseEdgeProcessor { EntityId entityId, JsonNode body, EdgeId sourceEdgeId) { - PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); - PageData pageData; List> futures = new ArrayList<>(); - do { - pageData = edgeService.findEdgesByTenantId(tenantId, pageLink); - if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { - for (Edge edge : pageData.getData()) { - if (!edge.getId().equals(sourceEdgeId)) { - futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, body)); - } - } - if (pageData.hasNext()) { - pageLink = pageLink.nextPageLink(); - } + PageDataIterable edges = new PageDataIterable<>(link -> edgeService.findEdgesByTenantId(tenantId, link), 1024); + for (Edge edge : edges) { + if (!edge.getId().equals(sourceEdgeId)) { + futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, body)); } - } while (pageData != null && pageData.hasNext()); + } return futures; } @@ -539,35 +532,24 @@ public abstract class BaseEdgeProcessor { } private ListenableFuture updateDependentRuleChains(TenantId tenantId, RuleChainId processingRuleChainId, EdgeId edgeId) { - PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); - PageData pageData; List> futures = new ArrayList<>(); - do { - pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, pageLink); - if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { - for (RuleChain ruleChain : pageData.getData()) { - if (!ruleChain.getId().equals(processingRuleChainId)) { - List connectionInfos = - ruleChainService.loadRuleChainMetaData(ruleChain.getTenantId(), ruleChain.getId()).getRuleChainConnections(); - if (connectionInfos != null && !connectionInfos.isEmpty()) { - for (RuleChainConnectionInfo connectionInfo : connectionInfos) { - if (connectionInfo.getTargetRuleChainId().equals(processingRuleChainId)) { - futures.add(saveEdgeEvent(tenantId, - edgeId, - EdgeEventType.RULE_CHAIN_METADATA, - EdgeEventActionType.UPDATED, - ruleChain.getId(), - null)); - } - } - } + PageDataIterable ruleChains = new PageDataIterable<>(link -> ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, link), 1024); + for (RuleChain ruleChain : ruleChains) { + List connectionInfos = + ruleChainService.loadRuleChainMetaData(ruleChain.getTenantId(), ruleChain.getId()).getRuleChainConnections(); + if (connectionInfos != null && !connectionInfos.isEmpty()) { + for (RuleChainConnectionInfo connectionInfo : connectionInfos) { + if (connectionInfo.getTargetRuleChainId().equals(processingRuleChainId)) { + futures.add(saveEdgeEvent(tenantId, + edgeId, + EdgeEventType.RULE_CHAIN_METADATA, + EdgeEventActionType.UPDATED, + ruleChain.getId(), + null)); } } - if (pageData.hasNext()) { - pageLink = pageLink.nextPageLink(); - } } - } while (pageData != null && pageData.hasNext()); + } return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService); } @@ -577,7 +559,7 @@ public abstract class BaseEdgeProcessor { case UPDATED: case DELETED: case CREDENTIALS_UPDATED: // used by USER entity - return processActionForAllEdges(tenantId, type, actionType, entityId, sourceEdgeId); + return processActionForAllEdges(tenantId, type, actionType, entityId, null, sourceEdgeId); default: return Futures.immediateFuture(null); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/customer/CustomerEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/customer/CustomerEdgeProcessor.java index 46daccfbe4..f6403629eb 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/customer/CustomerEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/customer/CustomerEdgeProcessor.java @@ -29,8 +29,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.EdgeVersion; @@ -85,20 +84,11 @@ public class CustomerEdgeProcessor extends BaseEdgeProcessor { CustomerId customerId = new CustomerId(EntityIdFactory.getByEdgeEventTypeAndUuid(type, uuid).getId()); switch (actionType) { case UPDATED: - PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); - PageData pageData; List> futures = new ArrayList<>(); - do { - pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); - if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { - for (Edge edge : pageData.getData()) { - futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, customerId, null)); - } - if (pageData.hasNext()) { - pageLink = pageLink.nextPageLink(); - } - } - } while (pageData != null && pageData.hasNext()); + PageDataIterable edges = new PageDataIterable<>(link -> edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, link), 1024); + for (Edge edge : edges) { + futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, customerId, null)); + } return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService); case DELETED: EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB())); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/oauth2/OAuth2EdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/oauth2/OAuth2EdgeProcessor.java new file mode 100644 index 0000000000..ce0600b491 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/oauth2/OAuth2EdgeProcessor.java @@ -0,0 +1,63 @@ +/** + * Copyright © 2016-2024 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.edge.rpc.processor.oauth2; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.EdgeUtils; +import org.thingsboard.server.common.data.edge.EdgeEvent; +import org.thingsboard.server.common.data.edge.EdgeEventActionType; +import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.oauth2.OAuth2Info; +import org.thingsboard.server.gen.edge.v1.DownlinkMsg; +import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; + +@Slf4j +@Component +@TbCoreComponent +public class OAuth2EdgeProcessor extends BaseEdgeProcessor { + + public DownlinkMsg convertOAuth2EventToDownlink(EdgeEvent edgeEvent) { + DownlinkMsg downlinkMsg = null; + OAuth2Info oAuth2Info = JacksonUtil.convertValue(edgeEvent.getBody(), OAuth2Info.class); + if (oAuth2Info != null) { + OAuth2UpdateMsg oAuth2UpdateMsg = oAuth2MsgConstructor.constructOAuth2UpdateMsg(oAuth2Info); + downlinkMsg = DownlinkMsg.newBuilder() + .setDownlinkMsgId(EdgeUtils.nextPositiveInt()) + .addOAuth2UpdateMsg(oAuth2UpdateMsg) + .build(); + } + return downlinkMsg; + } + + public ListenableFuture processOAuth2Notification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { + OAuth2Info oAuth2Info = JacksonUtil.fromString(edgeNotificationMsg.getBody(), OAuth2Info.class); + if (oAuth2Info == null) { + return Futures.immediateFuture(null); + } + EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); + EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); + return processActionForAllEdges(tenantId, type, actionType, null, JacksonUtil.toJsonNode(edgeNotificationMsg.getBody()), null); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java index 61d86994eb..73a3a2e25e 100644 --- a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java @@ -76,6 +76,7 @@ import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.v1.EdgeVersion; +import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg; import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg; import org.thingsboard.server.gen.edge.v1.SyncCompletedMsg; @@ -631,7 +632,7 @@ public class EdgeControllerTest extends AbstractControllerTest { List loadedEdges = new ArrayList<>(); PageLink pageLink = new PageLink(23); - PageData pageData = null; + PageData pageData; do { pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/edges?", new TypeReference<>() { @@ -885,6 +886,7 @@ public class EdgeControllerTest extends AbstractControllerTest { EdgeImitator edgeImitator = new EdgeImitator(EDGE_HOST, EDGE_PORT, edge.getRoutingKey(), edge.getSecret()); edgeImitator.ignoreType(UserCredentialsUpdateMsg.class); + edgeImitator.ignoreType(OAuth2UpdateMsg.class); edgeImitator.expectMessageAmount(24); edgeImitator.connect(); @@ -973,8 +975,7 @@ public class EdgeControllerTest extends AbstractControllerTest { private boolean popQueueMsg(List messages, UpdateMsgType msgType, String name) { for (AbstractMessage message : messages) { - if (message instanceof QueueUpdateMsg) { - QueueUpdateMsg queueUpdateMsg = (QueueUpdateMsg) message; + if (message instanceof QueueUpdateMsg queueUpdateMsg) { Queue queue = JacksonUtil.fromString(queueUpdateMsg.getEntity(), Queue.class, true); Assert.assertNotNull(queue); if (msgType.equals(queueUpdateMsg.getMsgType()) && name.equals(queue.getName())) { @@ -988,8 +989,7 @@ public class EdgeControllerTest extends AbstractControllerTest { private boolean popRuleChainMsg(List messages, UpdateMsgType msgType, String name) { for (AbstractMessage message : messages) { - if (message instanceof RuleChainUpdateMsg) { - RuleChainUpdateMsg ruleChainUpdateMsg = (RuleChainUpdateMsg) message; + if (message instanceof RuleChainUpdateMsg ruleChainUpdateMsg) { RuleChain ruleChain = JacksonUtil.fromString(ruleChainUpdateMsg.getEntity(), RuleChain.class, true); Assert.assertNotNull(ruleChain); if (msgType.equals(ruleChainUpdateMsg.getMsgType()) @@ -1005,8 +1005,7 @@ public class EdgeControllerTest extends AbstractControllerTest { private boolean popAdminSettingsMsg(List messages, String key) { for (AbstractMessage message : messages) { - if (message instanceof AdminSettingsUpdateMsg) { - AdminSettingsUpdateMsg adminSettingsUpdateMsg = (AdminSettingsUpdateMsg) message; + if (message instanceof AdminSettingsUpdateMsg adminSettingsUpdateMsg) { AdminSettings adminSettings = JacksonUtil.fromString(adminSettingsUpdateMsg.getEntity(), AdminSettings.class, true); Assert.assertNotNull(adminSettings); if (key.equals(adminSettings.getKey())) { @@ -1020,8 +1019,7 @@ public class EdgeControllerTest extends AbstractControllerTest { private boolean popDeviceProfileMsg(List messages, UpdateMsgType msgType, String name) { for (AbstractMessage message : messages) { - if (message instanceof DeviceProfileUpdateMsg) { - DeviceProfileUpdateMsg deviceProfileUpdateMsg = (DeviceProfileUpdateMsg) message; + if (message instanceof DeviceProfileUpdateMsg deviceProfileUpdateMsg) { DeviceProfile deviceProfile = JacksonUtil.fromString(deviceProfileUpdateMsg.getEntity(), DeviceProfile.class, true); Assert.assertNotNull(deviceProfile); if (msgType.equals(deviceProfileUpdateMsg.getMsgType()) @@ -1036,8 +1034,7 @@ public class EdgeControllerTest extends AbstractControllerTest { private boolean popDeviceMsg(List messages, UpdateMsgType msgType, String name) { for (AbstractMessage message : messages) { - if (message instanceof DeviceUpdateMsg) { - DeviceUpdateMsg deviceUpdateMsg = (DeviceUpdateMsg) message; + if (message instanceof DeviceUpdateMsg deviceUpdateMsg) { Device device = JacksonUtil.fromString(deviceUpdateMsg.getEntity(), Device.class, true); Assert.assertNotNull(device); if (msgType.equals(deviceUpdateMsg.getMsgType()) @@ -1052,8 +1049,7 @@ public class EdgeControllerTest extends AbstractControllerTest { private boolean popAssetProfileMsg(List messages, UpdateMsgType msgType, String name) { for (AbstractMessage message : messages) { - if (message instanceof AssetProfileUpdateMsg) { - AssetProfileUpdateMsg assetProfileUpdateMsg = (AssetProfileUpdateMsg) message; + if (message instanceof AssetProfileUpdateMsg assetProfileUpdateMsg) { AssetProfile assetProfile = JacksonUtil.fromString(assetProfileUpdateMsg.getEntity(), AssetProfile.class, true); Assert.assertNotNull(assetProfile); if (msgType.equals(assetProfileUpdateMsg.getMsgType()) @@ -1068,8 +1064,7 @@ public class EdgeControllerTest extends AbstractControllerTest { private boolean popAssetMsg(List messages, UpdateMsgType msgType, String name) { for (AbstractMessage message : messages) { - if (message instanceof AssetUpdateMsg) { - AssetUpdateMsg assetUpdateMsg = (AssetUpdateMsg) message; + if (message instanceof AssetUpdateMsg assetUpdateMsg) { Asset asset = JacksonUtil.fromString(assetUpdateMsg.getEntity(), Asset.class, true); Assert.assertNotNull(asset); if (msgType.equals(assetUpdateMsg.getMsgType()) @@ -1084,8 +1079,7 @@ public class EdgeControllerTest extends AbstractControllerTest { private boolean popUserMsg(List messages, UpdateMsgType msgType, String email, Authority authority) { for (AbstractMessage message : messages) { - if (message instanceof UserUpdateMsg) { - UserUpdateMsg userUpdateMsg = (UserUpdateMsg) message; + if (message instanceof UserUpdateMsg userUpdateMsg) { User user = JacksonUtil.fromString(userUpdateMsg.getEntity(), User.class, true); Assert.assertNotNull(user); if (msgType.equals(userUpdateMsg.getMsgType()) @@ -1101,8 +1095,7 @@ public class EdgeControllerTest extends AbstractControllerTest { private boolean popCustomerMsg(List messages, UpdateMsgType msgType, String title) { for (AbstractMessage message : messages) { - if (message instanceof CustomerUpdateMsg) { - CustomerUpdateMsg customerUpdateMsg = (CustomerUpdateMsg) message; + if (message instanceof CustomerUpdateMsg customerUpdateMsg) { Customer customer = JacksonUtil.fromString(customerUpdateMsg.getEntity(), Customer.class, true); Assert.assertNotNull(customer); if (msgType.equals(customerUpdateMsg.getMsgType()) @@ -1117,8 +1110,7 @@ public class EdgeControllerTest extends AbstractControllerTest { private boolean popTenantMsg(List messages, TenantId tenantId1) { for (AbstractMessage message : messages) { - if (message instanceof TenantUpdateMsg) { - TenantUpdateMsg tenantUpdateMsg = (TenantUpdateMsg) message; + if (message instanceof TenantUpdateMsg tenantUpdateMsg) { Tenant tenant = JacksonUtil.fromString(tenantUpdateMsg.getEntity(), Tenant.class, true); Assert.assertNotNull(tenant); if (UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE.equals(tenantUpdateMsg.getMsgType()) @@ -1133,8 +1125,7 @@ public class EdgeControllerTest extends AbstractControllerTest { private boolean popTenantProfileMsg(List messages, TenantProfileId tenantProfileId) { for (AbstractMessage message : messages) { - if (message instanceof TenantProfileUpdateMsg) { - TenantProfileUpdateMsg tenantProfileUpdateMsg = (TenantProfileUpdateMsg) message; + if (message instanceof TenantProfileUpdateMsg tenantProfileUpdateMsg) { TenantProfile tenantProfile = JacksonUtil.fromString(tenantProfileUpdateMsg.getEntity(), TenantProfile.class, true); Assert.assertNotNull(tenantProfile); if (UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE.equals(tenantProfileUpdateMsg.getMsgType()) @@ -1236,4 +1227,5 @@ public class EdgeControllerTest extends AbstractControllerTest { edgeUpgradeInstructionsService.setAppVersion("3.6.2.6"); Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); } + } diff --git a/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java b/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java index 8b0854983a..717c17d437 100644 --- a/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java @@ -494,7 +494,7 @@ public class HomePageApiTest extends AbstractControllerTest { } private OAuth2Info createDefaultOAuth2Info() { - return new OAuth2Info(true, Lists.newArrayList( + return new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("domain").scheme(SchemeType.MIXED).build() diff --git a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java index 0787d08fa7..e7f664477c 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java @@ -63,6 +63,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.oauth2.OAuth2Info; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.page.PageData; @@ -85,6 +86,7 @@ import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.v1.EdgeConfiguration; +import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg; import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataRequestMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; @@ -140,6 +142,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { installation(); edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret()); + edgeImitator.ignoreType(OAuth2UpdateMsg.class); edgeImitator.expectMessageAmount(21); edgeImitator.connect(); @@ -538,6 +541,18 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { Assert.assertTrue(customer.isPublic()); } + private void validateOAuth2() throws Exception { + Optional oAuth2UpdateMsgOpt = edgeImitator.findMessageByType(OAuth2UpdateMsg.class); + Assert.assertTrue(oAuth2UpdateMsgOpt.isPresent()); + OAuth2UpdateMsg oAuth2UpdateMsg = oAuth2UpdateMsgOpt.get(); + OAuth2Info oAuth2Info = JacksonUtil.fromString(oAuth2UpdateMsg.getEntity(), OAuth2Info.class, true); + Assert.assertNotNull(oAuth2Info); + OAuth2Info auth2Info = doGet("/api/oauth2/config", OAuth2Info.class); + Assert.assertNotNull(auth2Info); + Assert.assertEquals(oAuth2Info, auth2Info); + testAutoGeneratedCodeByProtobuf(oAuth2UpdateMsg); + } + private void validateSyncCompleted() { Optional syncCompletedMsgOpt = edgeImitator.findMessageByType(SyncCompletedMsg.class); Assert.assertTrue(syncCompletedMsgOpt.isPresent()); diff --git a/application/src/test/java/org/thingsboard/server/edge/OAuth2EdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/OAuth2EdgeTest.java new file mode 100644 index 0000000000..c25410b562 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/edge/OAuth2EdgeTest.java @@ -0,0 +1,113 @@ +/** + * Copyright © 2016-2024 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.edge; + +import com.google.common.collect.Lists; +import com.google.protobuf.AbstractMessage; +import org.junit.Assert; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.oauth2.MapperType; +import org.thingsboard.server.common.data.oauth2.OAuth2CustomMapperConfig; +import org.thingsboard.server.common.data.oauth2.OAuth2DomainInfo; +import org.thingsboard.server.common.data.oauth2.OAuth2Info; +import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig; +import org.thingsboard.server.common.data.oauth2.OAuth2ParamsInfo; +import org.thingsboard.server.common.data.oauth2.OAuth2RegistrationInfo; +import org.thingsboard.server.common.data.oauth2.SchemeType; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg; + +import java.util.Arrays; +import java.util.Collections; +import java.util.UUID; + +@DaoSqlTest +public class OAuth2EdgeTest extends AbstractEdgeTest { + + @Test + public void testOAuth2Support() throws Exception { + loginSysAdmin(); + + // enable oauth + edgeImitator.allowIgnoredTypes(); + edgeImitator.expectMessageAmount(1); + OAuth2Info oAuth2Info = createDefaultOAuth2Info(); + oAuth2Info = doPost("/api/oauth2/config", oAuth2Info, OAuth2Info.class); + Assert.assertTrue(edgeImitator.waitForMessages()); + AbstractMessage latestMessage = edgeImitator.getLatestMessage(); + Assert.assertTrue(latestMessage instanceof OAuth2UpdateMsg); + OAuth2UpdateMsg oAuth2UpdateMsg = (OAuth2UpdateMsg) latestMessage; + OAuth2Info result = JacksonUtil.fromString(oAuth2UpdateMsg.getEntity(), OAuth2Info.class, true); + Assert.assertEquals(oAuth2Info, result); + + // disable oauth support + edgeImitator.expectMessageAmount(1); + oAuth2Info.setEnabled(false); + oAuth2Info.setEdgeEnabled(false); + doPost("/api/oauth2/config", oAuth2Info, OAuth2Info.class); + Assert.assertTrue(edgeImitator.waitForMessages()); + latestMessage = edgeImitator.getLatestMessage(); + Assert.assertTrue(latestMessage instanceof OAuth2UpdateMsg); + oAuth2UpdateMsg = (OAuth2UpdateMsg) latestMessage; + result = JacksonUtil.fromString(oAuth2UpdateMsg.getEntity(), OAuth2Info.class, true); + Assert.assertEquals(oAuth2Info, result); + + edgeImitator.ignoreType(OAuth2UpdateMsg.class); + loginTenantAdmin(); + } + + private OAuth2Info createDefaultOAuth2Info() { + return new OAuth2Info(true, true, Lists.newArrayList( + OAuth2ParamsInfo.builder() + .domainInfos(Lists.newArrayList( + OAuth2DomainInfo.builder().name("domain").scheme(SchemeType.MIXED).build() + )) + .mobileInfos(Collections.emptyList()) + .clientRegistrations(Lists.newArrayList( + validRegistrationInfo() + )) + .build() + )); + } + + private OAuth2RegistrationInfo validRegistrationInfo() { + return OAuth2RegistrationInfo.builder() + .clientId(UUID.randomUUID().toString()) + .clientSecret(UUID.randomUUID().toString()) + .authorizationUri(UUID.randomUUID().toString()) + .accessTokenUri(UUID.randomUUID().toString()) + .scope(Arrays.asList(UUID.randomUUID().toString(), UUID.randomUUID().toString())) + .platforms(Collections.emptyList()) + .userInfoUri(UUID.randomUUID().toString()) + .userNameAttributeName(UUID.randomUUID().toString()) + .jwkSetUri(UUID.randomUUID().toString()) + .clientAuthenticationMethod(UUID.randomUUID().toString()) + .loginButtonLabel(UUID.randomUUID().toString()) + .mapperConfig( + OAuth2MapperConfig.builder() + .type(MapperType.CUSTOM) + .custom( + OAuth2CustomMapperConfig.builder() + .url(UUID.randomUUID().toString()) + .build() + ) + .build() + ) + .build(); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java index 916e5790e9..12405a7d5f 100644 --- a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java +++ b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java @@ -44,6 +44,7 @@ import org.thingsboard.server.gen.edge.v1.DownlinkResponseMsg; import org.thingsboard.server.gen.edge.v1.EdgeConfiguration; import org.thingsboard.server.gen.edge.v1.EntityDataProto; import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg; +import org.thingsboard.server.gen.edge.v1.OAuth2UpdateMsg; import org.thingsboard.server.gen.edge.v1.OtaPackageUpdateMsg; import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg; import org.thingsboard.server.gen.edge.v1.RelationUpdateMsg; @@ -314,6 +315,11 @@ public class EdgeImitator { result.add(saveDownlinkMsg(resourceUpdateMsg)); } } + if (downlinkMsg.getOAuth2UpdateMsgCount() > 0) { + for (OAuth2UpdateMsg oAuth2UpdateMsg : downlinkMsg.getOAuth2UpdateMsgList()) { + result.add(saveDownlinkMsg(oAuth2UpdateMsg)); + } + } if (downlinkMsg.hasEdgeConfiguration()) { result.add(saveDownlinkMsg(downlinkMsg.getEdgeConfiguration())); } diff --git a/application/src/test/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessorTest.java b/application/src/test/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessorTest.java index ba8eda3879..4e5b080b65 100644 --- a/application/src/test/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessorTest.java +++ b/application/src/test/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessorTest.java @@ -46,6 +46,7 @@ import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeSynchronizationManager; import org.thingsboard.server.dao.entityview.EntityViewService; +import org.thingsboard.server.dao.oauth2.OAuth2Service; import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; @@ -81,6 +82,7 @@ import org.thingsboard.server.service.edge.rpc.constructor.edge.EdgeMsgConstruct import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorV1; import org.thingsboard.server.service.edge.rpc.constructor.entityview.EntityViewMsgConstructorV2; +import org.thingsboard.server.service.edge.rpc.constructor.oauth2.OAuth2MsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorFactory; import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorV1; import org.thingsboard.server.service.edge.rpc.constructor.ota.OtaPackageMsgConstructorV2; @@ -128,6 +130,7 @@ import org.thingsboard.server.service.edge.rpc.processor.device.profile.DevicePr import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorFactory; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorV1; import org.thingsboard.server.service.edge.rpc.processor.entityview.EntityViewProcessorV2; +import org.thingsboard.server.service.edge.rpc.processor.oauth2.OAuth2EdgeProcessor; import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessorFactory; import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessorV1; import org.thingsboard.server.service.edge.rpc.processor.relation.RelationEdgeProcessorV2; @@ -239,6 +242,9 @@ public abstract class BaseEdgeProcessorTest { @MockBean protected ResourceService resourceService; + @MockBean + protected OAuth2Service oAuth2Service; + @MockBean @Lazy protected TbQueueProducerProvider producerProvider; @@ -360,6 +366,9 @@ public abstract class BaseEdgeProcessorTest { @MockBean protected WidgetMsgConstructorV2 widgetMsgConstructorV2; + @MockBean + protected OAuth2MsgConstructor oAuth2MsgConstructor; + @MockBean protected AlarmEdgeProcessorV1 alarmProcessorV1; @@ -417,6 +426,9 @@ public abstract class BaseEdgeProcessorTest { @MockBean protected RelationEdgeProcessorV2 relationEdgeProcessorV2; + @MockBean + protected OAuth2EdgeProcessor oAuth2EdgeProcessor; + @SpyBean protected RuleChainMsgConstructorFactory ruleChainMsgConstructorFactory; diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java index 941432b879..11129002e7 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Service.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.UUID; public interface OAuth2Service { + List getOAuth2Clients(String domainScheme, String domainName, String pkgName, PlatformType platformType); void saveOAuth2Info(OAuth2Info oauth2Info); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java index 6fc255501f..783bb3ffd5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java @@ -41,7 +41,8 @@ public enum EdgeEventType { ADMIN_SETTINGS(true, null), OTA_PACKAGE(true, EntityType.OTA_PACKAGE), QUEUE(true, EntityType.QUEUE), - TB_RESOURCE(true, EntityType.TB_RESOURCE); + TB_RESOURCE(true, EntityType.TB_RESOURCE), + OAUTH2(true, null); private final boolean allEdgesRelated; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java index c163647d49..034070f57c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Info.java @@ -35,6 +35,8 @@ import java.util.List; public class OAuth2Info { @Schema(description = "Whether OAuth2 settings are enabled or not") private boolean enabled; + @Schema(description = "Whether OAuth2 settings are enabled on Edge or not") + private boolean edgeEnabled; @Schema(description = "List of configured OAuth2 clients. Cannot contain null values", required = true) private List oauth2ParamsInfos; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Params.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Params.java index 3f847c2f9e..70020fc7cd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Params.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Params.java @@ -30,11 +30,13 @@ import org.thingsboard.server.common.data.id.TenantId; public class OAuth2Params extends BaseData { private boolean enabled; + private boolean edgeEnabled; private TenantId tenantId; public OAuth2Params(OAuth2Params oauth2Params) { super(oauth2Params); this.enabled = oauth2Params.enabled; + this.edgeEnabled = oauth2Params.edgeEnabled; this.tenantId = oauth2Params.tenantId; } } diff --git a/common/edge-api/src/main/proto/edge.proto b/common/edge-api/src/main/proto/edge.proto index 34a8c6f093..4ac1831601 100644 --- a/common/edge-api/src/main/proto/edge.proto +++ b/common/edge-api/src/main/proto/edge.proto @@ -467,6 +467,10 @@ message ResourceUpdateMsg { string entity = 11; } +message OAuth2UpdateMsg { + string entity = 1; +} + message RuleChainMetadataRequestMsg { int64 ruleChainIdMSB = 1; int64 ruleChainIdLSB = 2; @@ -668,5 +672,6 @@ message DownlinkMsg { repeated TenantProfileUpdateMsg tenantProfileUpdateMsg = 27; repeated ResourceUpdateMsg resourceUpdateMsg = 28; repeated AlarmCommentUpdateMsg alarmCommentUpdateMsg = 29; + repeated OAuth2UpdateMsg oAuth2UpdateMsg = 30; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 2fe56f5d1f..d5c120393c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -427,6 +427,7 @@ public class ModelConstants { */ public static final String OAUTH2_PARAMS_TABLE_NAME = "oauth2_params"; public static final String OAUTH2_PARAMS_ENABLED_PROPERTY = "enabled"; + public static final String OAUTH2_PARAMS_EDGE_ENABLED_PROPERTY = "edge_enabled"; public static final String OAUTH2_PARAMS_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String OAUTH2_REGISTRATION_TABLE_NAME = "oauth2_registration"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ParamsEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ParamsEntity.java index adbbeb7fd8..4983172d3e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ParamsEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/OAuth2ParamsEntity.java @@ -39,6 +39,9 @@ public class OAuth2ParamsEntity extends BaseSqlEntity { @Column(name = ModelConstants.OAUTH2_PARAMS_ENABLED_PROPERTY) private Boolean enabled; + @Column(name = ModelConstants.OAUTH2_PARAMS_EDGE_ENABLED_PROPERTY) + private Boolean edgeEnabled; + @Column(name = ModelConstants.OAUTH2_PARAMS_TENANT_ID_PROPERTY) private UUID tenantId; @@ -48,6 +51,7 @@ public class OAuth2ParamsEntity extends BaseSqlEntity { } this.setCreatedTime(oauth2Params.getCreatedTime()); this.enabled = oauth2Params.isEnabled(); + this.edgeEnabled = oauth2Params.isEdgeEnabled(); if (oauth2Params.getTenantId() != null) { this.tenantId = oauth2Params.getTenantId().getId(); } @@ -60,6 +64,7 @@ public class OAuth2ParamsEntity extends BaseSqlEntity { oauth2Params.setCreatedTime(createdTime); oauth2Params.setTenantId(TenantId.fromUUID(tenantId)); oauth2Params.setEnabled(enabled); + oauth2Params.setEdgeEnabled(edgeEnabled); return oauth2Params; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java index 58be6a0770..d28830165d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ServiceImpl.java @@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.oauth2.PlatformType; import org.thingsboard.server.common.data.oauth2.SchemeType; import org.thingsboard.server.common.data.oauth2.TenantNameStrategyType; import org.thingsboard.server.dao.entity.AbstractEntityService; +import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.IncorrectParameterException; @@ -58,6 +59,7 @@ import static org.thingsboard.server.dao.service.Validator.validateString; @Slf4j @Service public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Service { + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; public static final String INCORRECT_CLIENT_REGISTRATION_ID = "Incorrect clientRegistrationId "; public static final String INCORRECT_DOMAIN_NAME = "Incorrect domainName "; @@ -116,6 +118,7 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se }); } }); + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(TenantId.SYS_TENANT_ID).entity(oauth2Info).build()); } @Override @@ -123,7 +126,8 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se log.trace("Executing findOAuth2Info"); OAuth2Info oauth2Info = new OAuth2Info(); List oauth2ParamsList = oauth2ParamsDao.find(TenantId.SYS_TENANT_ID); - oauth2Info.setEnabled(oauth2ParamsList.stream().anyMatch(param -> param.isEnabled())); + oauth2Info.setEnabled(oauth2ParamsList.stream().anyMatch(OAuth2Params::isEnabled)); + oauth2Info.setEdgeEnabled(oauth2ParamsList.stream().anyMatch(OAuth2Params::isEdgeEnabled)); List oauth2ParamsInfos = new ArrayList<>(); oauth2Info.setOauth2ParamsInfos(oauth2ParamsInfos); oauth2ParamsList.stream().sorted(Comparator.comparing(BaseData::getUuidId)).forEach(oauth2Params -> { diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Utils.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Utils.java index 4e22ea858b..8d30fc905d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Utils.java +++ b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2Utils.java @@ -88,6 +88,7 @@ public class OAuth2Utils { public static OAuth2Params infoToOAuth2Params(OAuth2Info oauth2Info) { OAuth2Params oauth2Params = new OAuth2Params(); oauth2Params.setEnabled(oauth2Info.isEnabled()); + oauth2Params.setEdgeEnabled(oauth2Info.isEdgeEnabled()); oauth2Params.setTenantId(TenantId.SYS_TENANT_ID); return oauth2Params; } diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 2dce04d67f..71e447049b 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -559,6 +559,7 @@ CREATE TABLE IF NOT EXISTS key_dictionary CREATE TABLE IF NOT EXISTS oauth2_params ( id uuid NOT NULL CONSTRAINT oauth2_params_pkey PRIMARY KEY, enabled boolean, + edge_enabled boolean, tenant_id uuid, created_time bigint NOT NULL ); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/OAuth2ServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/OAuth2ServiceTest.java index ae9aa72be9..281709c9af 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/OAuth2ServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/OAuth2ServiceTest.java @@ -47,7 +47,7 @@ import java.util.stream.Collectors; @DaoSqlTest public class OAuth2ServiceTest extends AbstractServiceTest { - private static final OAuth2Info EMPTY_PARAMS = new OAuth2Info(false, Collections.emptyList()); + private static final OAuth2Info EMPTY_PARAMS = new OAuth2Info(false, false, Collections.emptyList()); @Autowired protected OAuth2Service oAuth2Service; @@ -66,7 +66,7 @@ public class OAuth2ServiceTest extends AbstractServiceTest { @Test public void testSaveHttpAndMixedDomainsTogether() { - OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList( + OAuth2Info oAuth2Info = new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), @@ -87,7 +87,7 @@ public class OAuth2ServiceTest extends AbstractServiceTest { @Test public void testSaveHttpsAndMixedDomainsTogether() { - OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList( + OAuth2Info oAuth2Info = new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTPS).build(), @@ -153,7 +153,7 @@ public class OAuth2ServiceTest extends AbstractServiceTest { Assert.assertNotNull(foundOAuth2Info); Assert.assertEquals(oAuth2Info, foundOAuth2Info); - OAuth2Info newOAuth2Info = new OAuth2Info(true, Lists.newArrayList( + OAuth2Info newOAuth2Info = new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("another-domain").scheme(SchemeType.HTTPS).build() @@ -194,7 +194,7 @@ public class OAuth2ServiceTest extends AbstractServiceTest { List thirdGroup = Lists.newArrayList( validRegistrationInfo() ); - OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList( + OAuth2Info oAuth2Info = new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), @@ -318,7 +318,7 @@ public class OAuth2ServiceTest extends AbstractServiceTest { validRegistrationInfo(), validRegistrationInfo() ); - OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList( + OAuth2Info oAuth2Info = new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), @@ -363,7 +363,7 @@ public class OAuth2ServiceTest extends AbstractServiceTest { @Test public void testGetDisabledOAuth2Clients() { - OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList( + OAuth2Info oAuth2Info = new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), @@ -402,7 +402,7 @@ public class OAuth2ServiceTest extends AbstractServiceTest { @Test public void testFindAllRegistrations() { - OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList( + OAuth2Info oAuth2Info = new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), @@ -451,7 +451,7 @@ public class OAuth2ServiceTest extends AbstractServiceTest { @Test public void testFindRegistrationById() { - OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList( + OAuth2Info oAuth2Info = new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), @@ -495,7 +495,7 @@ public class OAuth2ServiceTest extends AbstractServiceTest { @Test public void testFindAppSecret() { - OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList( + OAuth2Info oAuth2Info = new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), @@ -547,7 +547,7 @@ public class OAuth2ServiceTest extends AbstractServiceTest { @Test public void testFindClientsByPackageAndPlatform() { - OAuth2Info oAuth2Info = new OAuth2Info(true, Lists.newArrayList( + OAuth2Info oAuth2Info = new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), @@ -596,7 +596,7 @@ public class OAuth2ServiceTest extends AbstractServiceTest { } private OAuth2Info createDefaultOAuth2Info() { - return new OAuth2Info(true, Lists.newArrayList( + return new OAuth2Info(true, false, Lists.newArrayList( OAuth2ParamsInfo.builder() .domainInfos(Lists.newArrayList( OAuth2DomainInfo.builder().name("first-domain").scheme(SchemeType.HTTP).build(), @@ -664,4 +664,5 @@ public class OAuth2ServiceTest extends AbstractServiceTest { .appSecret(appSecret != null ? appSecret : StringUtils.randomAlphanumeric(24)) .build(); } + } diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html index b01f37a717..2e85f8b54b 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html @@ -29,13 +29,18 @@
-
- - {{ 'admin.oauth2.enable' | translate }} - -
+
+
+ + {{ 'admin.oauth2.enable' | translate }} + + + {{ 'admin.oauth2.edge-enable' | translate }} + +
+
-
+
diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss index a476f438e3..639fb877f2 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss @@ -13,7 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@import '../../../../../scss/constants'; + :host{ + .gap-xs-12 { + @media #{$mat-xs} { + gap: 12px; + } + } + + .mdc-evolution-chip-set .mdc-evolution-chip { + margin-top: 0; + margin-bottom: 0; + } + .checkbox-row { margin-top: 1em; } @@ -31,7 +44,7 @@ } .container{ - margin-bottom: 1em; + margin-bottom: 16px; .tb-highlight{ margin: 0; diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts index 1d346c70f1..f6f8340550 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts @@ -204,13 +204,23 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha private buildOAuth2SettingsForm(): void { this.oauth2SettingsForm = this.fb.group({ oauth2ParamsInfos: this.fb.array([]), - enabled: [false] + enabled: [false], + edgeEnabled: [{value: false, disabled: true}] }); + + this.subscriptions.push(this.oauth2SettingsForm.get('enabled').valueChanges.subscribe(enabled => { + if (enabled) { + this.oauth2SettingsForm.get('edgeEnabled').enable(); + } else { + this.oauth2SettingsForm.get('edgeEnabled').patchValue(false); + this.oauth2SettingsForm.get('edgeEnabled').disable(); + } + })) } private initOAuth2Settings(oauth2Info: OAuth2Info): void { if (oauth2Info) { - this.oauth2SettingsForm.patchValue({enabled: oauth2Info.enabled}, {emitEvent: false}); + this.oauth2SettingsForm.patchValue({enabled: oauth2Info.enabled, edgeEnabled: oauth2Info.edgeEnabled}); oauth2Info.oauth2ParamsInfos.forEach((oauth2ParamsInfo) => { this.oauth2ParamsInfos.push(this.buildOAuth2ParamsInfoForm(oauth2ParamsInfo)); }); diff --git a/ui-ngx/src/app/shared/models/oauth2.models.ts b/ui-ngx/src/app/shared/models/oauth2.models.ts index b77a5f5888..9e3d3fa1c5 100644 --- a/ui-ngx/src/app/shared/models/oauth2.models.ts +++ b/ui-ngx/src/app/shared/models/oauth2.models.ts @@ -18,6 +18,7 @@ import { HasUUID } from '@shared/models/id/has-uuid'; export interface OAuth2Info { enabled: boolean; + edgeEnabled: boolean; oauth2ParamsInfos: OAuth2ParamsInfo[]; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index f8f752b5b3..a317b9b89d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -283,6 +283,7 @@ "domain-schema-https": "HTTPS", "domain-schema-mixed": "HTTP+HTTPS", "enable": "Enable OAuth2 settings", + "edge-enable": "Propagate to Edge", "domains": "Domains", "mobile-apps": "Mobile applications", "no-mobile-apps": "No applications configured",