diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java index 0cb5be92ee..6b77460bfb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java @@ -141,7 +141,7 @@ public class JpaUserDao extends JpaAbstractDao implements User @Override public UserAuthDetails findUserAuthDetailsByUserId(UUID tenantId, UUID userId) { TbPair result = userRepository.findUserAuthDetailsByUserId(userId); - return new UserAuthDetails(result.getFirst().toData(), result.getSecond()); + return result != null ? new UserAuthDetails(result.getFirst().toData(), result.getSecond()) : null; } @Override diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/JavaRestClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/JavaRestClientTest.java index fb41cdf77f..5b98f4859b 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/JavaRestClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/JavaRestClientTest.java @@ -76,6 +76,8 @@ import org.thingsboard.server.common.data.oauth2.PlatformType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.pat.ApiKey; +import org.thingsboard.server.common.data.pat.ApiKeyInfo; import org.thingsboard.server.common.data.query.AvailableEntityKeys; import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; @@ -93,6 +95,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; import static org.thingsboard.server.common.data.notification.NotificationDeliveryMethod.EMAIL; @@ -318,7 +321,7 @@ public class JavaRestClientTest extends AbstractContainerTest { Domain savedDomain = restClient.saveDomain(domain); assertThat(savedDomain.getName()).isEqualTo(domain.getName()); - PageData domainInfos = restClient.getTenantDomainInfos(new PageLink(10, 0 , prefix)); + PageData domainInfos = restClient.getTenantDomainInfos(new PageLink(10, 0, prefix)); assertThat(domainInfos.getData()).hasSize(1); } @@ -354,7 +357,7 @@ public class JavaRestClientTest extends AbstractContainerTest { filter.setUsersIds(Arrays.stream(usersIds).map(UUIDBased::getId).toList()); NotificationTarget notificationTarget = new NotificationTarget(); - notificationTarget.setName(filter.toString() + org.apache.commons.lang3.RandomStringUtils.randomNumeric(5)); + notificationTarget.setName(filter + RandomStringUtils.randomNumeric(5)); PlatformUsersNotificationTargetConfig targetConfig = new PlatformUsersNotificationTargetConfig(); targetConfig.setUsersFilter(filter); notificationTarget.setConfiguration(targetConfig); @@ -362,7 +365,7 @@ public class JavaRestClientTest extends AbstractContainerTest { } private NotificationTemplate createNotificationTemplate(NotificationType notificationType, String subject, - String text, NotificationDeliveryMethod... deliveryMethods) { + String text, NotificationDeliveryMethod... deliveryMethods) { NotificationTemplate notificationTemplate = new NotificationTemplate(); notificationTemplate.setName("Notification template: " + RandomStringUtils.randomAlphabetic(5)); notificationTemplate.setNotificationType(notificationType); @@ -404,10 +407,59 @@ public class JavaRestClientTest extends AbstractContainerTest { NotificationRequestConfig config = new NotificationRequestConfig(); config.setSendingDelayInSec(0); NotificationRequest notificationRequest = NotificationRequest.builder() - .targets(List.of(targetId).stream().map(UUIDBased::getId).collect(Collectors.toList())) + .targets(Stream.of(targetId).map(UUIDBased::getId).collect(Collectors.toList())) .templateId(notificationTemplateId) .additionalConfig(config) .build(); return restClient.saveNotificationRequest(notificationRequest); } + + @Test + public void testApiKeyOperations() { + // Create an API key + ApiKeyInfo apiKeyInfo = new ApiKeyInfo(); + apiKeyInfo.setDescription("Test API Key " + RandomStringUtils.randomAlphabetic(5)); + apiKeyInfo.setEnabled(true); + apiKeyInfo.setUserId(user.getId()); + apiKeyInfo.setExpirationTime(0); + + ApiKey savedApiKey = restClient.saveApiKey(apiKeyInfo); + assertThat(savedApiKey).isNotNull(); + assertThat(savedApiKey.getId()).isNotNull(); + assertThat(savedApiKey.getDescription()).isEqualTo(apiKeyInfo.getDescription()); + assertThat(savedApiKey.isEnabled()).isTrue(); + assertThat(savedApiKey.getUserId()).isEqualTo(user.getId()); + assertThat(savedApiKey.getTenantId()).isEqualTo(tenant.getId()); + assertThat(savedApiKey.getValue()).isNotNull(); + + // Get user API keys + PageData apiKeys = restClient.getUserApiKeys(user.getId(), new PageLink(10)); + assertThat(apiKeys).isNotNull(); + assertThat(apiKeys.getData()).hasSize(1); + assertThat(apiKeys.getData().get(0).getId()).isEqualTo(savedApiKey.getId()); + + // Update API key description + String updatedDescription = "Updated description " + RandomStringUtils.randomAlphabetic(5); + ApiKeyInfo updatedApiKeyInfo = restClient.updateApiKeyDescription(savedApiKey.getId(), updatedDescription); + assertThat(updatedApiKeyInfo).isNotNull(); + assertThat(updatedApiKeyInfo.getDescription()).isEqualTo(updatedDescription); + + // Disable the API key + ApiKeyInfo disabledApiKey = restClient.enableApiKey(savedApiKey.getId(), false); + assertThat(disabledApiKey).isNotNull(); + assertThat(disabledApiKey.isEnabled()).isFalse(); + + // Enable the API key + ApiKeyInfo enabledApiKey = restClient.enableApiKey(savedApiKey.getId(), true); + assertThat(enabledApiKey).isNotNull(); + assertThat(enabledApiKey.isEnabled()).isTrue(); + + // Delete the API key + restClient.deleteApiKey(savedApiKey.getId()); + + // Verify the API key is deleted + PageData apiKeysAfterDelete = restClient.getUserApiKeys(user.getId(), new PageLink(10)); + assertThat(apiKeysAfterDelete.getData()).isEmpty(); + } + } diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index c82a80e7cc..7686949980 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -105,6 +105,7 @@ import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.id.AiModelId; import org.thingsboard.server.common.data.id.AlarmCommentId; import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.ApiKeyId; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.CalculatedFieldId; @@ -156,6 +157,8 @@ import org.thingsboard.server.common.data.oauth2.PlatformType; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.pat.ApiKey; +import org.thingsboard.server.common.data.pat.ApiKeyInfo; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; @@ -290,6 +293,10 @@ public class RestClient implements Closeable { }); } + public static RestClient withApiKey(String baseURL, String token) { + return withApiKey(new RestTemplate(), baseURL, token); + } + public static RestClient withApiKey(RestTemplate rt, String baseURL, String token) { return new RestClient(rt, baseURL, AuthType.API_KEY, token); } @@ -3043,6 +3050,44 @@ public class RestClient implements Closeable { userCredentialsEnabled); } + public ApiKey saveApiKey(ApiKeyInfo apiKeyInfo) { + return restTemplate.postForEntity(baseURL + "/api/apiKey", apiKeyInfo, ApiKey.class).getBody(); + } + + public PageData getUserApiKeys(UserId userId, PageLink pageLink) { + Map params = new HashMap<>(); + params.put("userId", userId.getId().toString()); + addPageLinkToParam(params, pageLink); + return restTemplate.exchange( + baseURL + "/api/apiKeys/{userId}?" + getUrlParams(pageLink), + HttpMethod.GET, + HttpEntity.EMPTY, + new ParameterizedTypeReference>() {}, params).getBody(); + } + + public ApiKeyInfo updateApiKeyDescription(ApiKeyId apiKeyId, String description) { + return restTemplate.exchange( + baseURL + "/api/apiKey/{id}/description", + HttpMethod.PUT, + new HttpEntity<>(description), + ApiKeyInfo.class, + apiKeyId.getId()).getBody(); + } + + public ApiKeyInfo enableApiKey(ApiKeyId apiKeyId, boolean enabled) { + return restTemplate.exchange( + baseURL + "/api/apiKey/{id}/enabled/{enabledValue}", + HttpMethod.PUT, + HttpEntity.EMPTY, + ApiKeyInfo.class, + apiKeyId.getId(), + enabled).getBody(); + } + + public void deleteApiKey(ApiKeyId apiKeyId) { + restTemplate.delete(baseURL + "/api/apiKey/{id}", apiKeyId.getId()); + } + public Optional getWidgetsBundleById(WidgetsBundleId widgetsBundleId) { try { ResponseEntity widgetsBundle =