Merge pull request #9104 from thingsboard/feature/system-notifications
Notification to sysadmin when default JWT signing key is used
This commit is contained in:
commit
6f2334b35b
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright © 2016-2023 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.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
@Configuration
|
||||
public class CryptoConfig {
|
||||
|
||||
@Bean
|
||||
protected BCryptPasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
}
|
||||
@ -188,11 +188,6 @@ public class ThingsboardSecurityConfiguration {
|
||||
return auth.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected BCryptPasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver;
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.rule.engine.api.NotificationCenter;
|
||||
import org.thingsboard.server.common.data.EntityType;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.NotificationId;
|
||||
import org.thingsboard.server.common.data.id.NotificationRequestId;
|
||||
import org.thingsboard.server.common.data.id.NotificationRuleId;
|
||||
@ -39,11 +40,12 @@ import org.thingsboard.server.common.data.notification.NotificationRequestStatus
|
||||
import org.thingsboard.server.common.data.notification.NotificationStatus;
|
||||
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
|
||||
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
|
||||
import org.thingsboard.server.common.data.notification.targets.MicrosoftTeamsNotificationTargetConfig;
|
||||
import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings;
|
||||
import org.thingsboard.server.common.data.notification.targets.MicrosoftTeamsNotificationTargetConfig;
|
||||
import org.thingsboard.server.common.data.notification.targets.NotificationRecipient;
|
||||
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter;
|
||||
import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig;
|
||||
import org.thingsboard.server.common.data.notification.template.DeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
|
||||
@ -165,16 +167,54 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
|
||||
.settings(settings)
|
||||
.build();
|
||||
|
||||
notificationExecutor.submit(() -> {
|
||||
for (NotificationTarget target : targets) {
|
||||
processForTarget(target, ctx);
|
||||
processNotificationRequestAsync(ctx, targets, callback);
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendGeneralWebNotification(TenantId tenantId, UsersFilter recipients, NotificationTemplate template) {
|
||||
NotificationTarget target = new NotificationTarget();
|
||||
target.setTenantId(tenantId);
|
||||
PlatformUsersNotificationTargetConfig targetConfig = new PlatformUsersNotificationTargetConfig();
|
||||
targetConfig.setUsersFilter(recipients);
|
||||
target.setConfiguration(targetConfig);
|
||||
|
||||
NotificationRequest notificationRequest = NotificationRequest.builder()
|
||||
.tenantId(tenantId)
|
||||
.template(template)
|
||||
.targets(List.of(EntityId.NULL_UUID)) // this is temporary and will be removed when 'create from scratch' functionality is implemented for recipients
|
||||
.status(NotificationRequestStatus.PROCESSING)
|
||||
.build();
|
||||
try {
|
||||
notificationRequest = notificationRequestService.saveNotificationRequest(tenantId, notificationRequest);
|
||||
NotificationProcessingContext ctx = NotificationProcessingContext.builder()
|
||||
.tenantId(tenantId)
|
||||
.request(notificationRequest)
|
||||
.deliveryMethods(Set.of(NotificationDeliveryMethod.WEB))
|
||||
.template(template)
|
||||
.build();
|
||||
|
||||
processNotificationRequestAsync(ctx, List.of(target), null);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to process notification request for recipients {} for template '{}'", recipients, template.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void processNotificationRequestAsync(NotificationProcessingContext ctx, List<NotificationTarget> targets, Consumer<NotificationRequestStats> callback) {
|
||||
notificationExecutor.submit(() -> {
|
||||
NotificationRequestId requestId = ctx.getRequest().getId();
|
||||
for (NotificationTarget target : targets) {
|
||||
try {
|
||||
processForTarget(target, ctx);
|
||||
} catch (Exception e) {
|
||||
log.error("[{}] Failed to process notification request for target {}", requestId, target.getId(), e);
|
||||
}
|
||||
}
|
||||
log.debug("[{}] Notification request processing is finished", requestId);
|
||||
|
||||
NotificationRequestStats stats = ctx.getStats();
|
||||
try {
|
||||
notificationRequestService.updateNotificationRequest(tenantId, requestId, NotificationRequestStatus.SENT, stats);
|
||||
notificationRequestService.updateNotificationRequest(ctx.getTenantId(), requestId, NotificationRequestStatus.SENT, stats);
|
||||
} catch (Exception e) {
|
||||
log.error("[{}] Failed to update stats for notification request", requestId, e);
|
||||
}
|
||||
@ -187,8 +227,6 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private void processForTarget(NotificationTarget target, NotificationProcessingContext ctx) {
|
||||
|
||||
@ -22,11 +22,14 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.NotificationCenter;
|
||||
import org.thingsboard.server.cluster.TbClusterService;
|
||||
import org.thingsboard.server.common.data.AdminSettings;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.SystemAdministratorsFilter;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
|
||||
import org.thingsboard.server.common.data.security.model.JwtSettings;
|
||||
import org.thingsboard.server.dao.notification.DefaultNotifications;
|
||||
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -43,6 +46,7 @@ public class DefaultJwtSettingsService implements JwtSettingsService {
|
||||
private final AdminSettingsService adminSettingsService;
|
||||
@Lazy
|
||||
private final Optional<TbClusterService> tbClusterService;
|
||||
private final Optional<NotificationCenter> notificationCenter;
|
||||
private final JwtSettingsValidator jwtSettingsValidator;
|
||||
|
||||
@Value("${security.jwt.tokenExpirationTime:9000}")
|
||||
@ -124,6 +128,9 @@ public class DefaultJwtSettingsService implements JwtSettingsService {
|
||||
log.warn("WARNING: The platform is configured to use default JWT Signing Key. " +
|
||||
"This is a security issue that needs to be resolved. Please change the JWT Signing Key using the Web UI. " +
|
||||
"Navigate to \"System settings -> Security settings\" while logged in as a System Administrator.");
|
||||
notificationCenter.ifPresent(notificationCenter -> {
|
||||
notificationCenter.sendGeneralWebNotification(TenantId.SYS_TENANT_ID, new SystemAdministratorsFilter(), DefaultNotifications.jwtSigningKeyIssue.toTemplate());
|
||||
});
|
||||
}
|
||||
this.jwtSettings = result;
|
||||
}
|
||||
|
||||
@ -55,7 +55,6 @@ import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
||||
import org.thingsboard.server.dao.user.UserService;
|
||||
import org.thingsboard.server.dao.user.UserServiceImpl;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails;
|
||||
import org.thingsboard.server.service.security.exception.UserPasswordExpiredException;
|
||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||
@ -73,7 +72,6 @@ import static org.thingsboard.server.common.data.CacheConstants.SECURITY_SETTING
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@TbCoreComponent
|
||||
public class DefaultSystemSecurityService implements SystemSecurityService {
|
||||
|
||||
@Autowired
|
||||
|
||||
@ -265,4 +265,8 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest
|
||||
return (NotificationApiWsClient) super.getWsClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationApiWsClient getAnotherWsClient() {
|
||||
return (NotificationApiWsClient) super.getAnotherWsClient();
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.audit.ActionType;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.NotificationRuleId;
|
||||
import org.thingsboard.server.common.data.id.NotificationTargetId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.notification.Notification;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequest;
|
||||
@ -47,6 +48,7 @@ import org.thingsboard.server.common.data.notification.targets.MicrosoftTeamsNot
|
||||
import org.thingsboard.server.common.data.notification.targets.NotificationTarget;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.CustomerUsersFilter;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.SystemAdministratorsFilter;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.UserListFilter;
|
||||
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversation;
|
||||
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversationType;
|
||||
@ -61,6 +63,7 @@ import org.thingsboard.server.common.data.notification.template.SlackDeliveryMet
|
||||
import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
import org.thingsboard.server.dao.notification.DefaultNotifications;
|
||||
import org.thingsboard.server.dao.notification.NotificationDao;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
|
||||
@ -601,6 +604,23 @@ public class NotificationApiTest extends AbstractNotificationApiTest {
|
||||
assertThat(stats.getErrors().get(NotificationDeliveryMethod.SLACK).values()).containsExactly(errorMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInternalGeneralWebNotifications() throws Exception {
|
||||
loginSysAdmin();
|
||||
getAnotherWsClient().subscribeForUnreadNotifications(10).waitForReply(true);
|
||||
|
||||
getAnotherWsClient().registerWaitForUpdate();
|
||||
|
||||
DefaultNotifications.DefaultNotification expectedNotification = DefaultNotifications.maintenanceWork;
|
||||
notificationCenter.sendGeneralWebNotification(TenantId.SYS_TENANT_ID, new SystemAdministratorsFilter(),
|
||||
expectedNotification.toTemplate());
|
||||
|
||||
getAnotherWsClient().waitForUpdate(true);
|
||||
Notification notification = getAnotherWsClient().getLastDataUpdate().getUpdate();
|
||||
assertThat(notification.getSubject()).isEqualTo(expectedNotification.getSubject());
|
||||
assertThat(notification.getText()).isEqualTo(expectedNotification.getText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMicrosoftTeamsNotifications() throws Exception {
|
||||
RestTemplate restTemplate = mock(RestTemplate.class);
|
||||
@ -688,7 +708,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest {
|
||||
|
||||
protected void connectOtherWsClient() throws Exception {
|
||||
loginCustomerUser();
|
||||
otherWsClient = (NotificationApiWsClient) super.getAnotherWsClient();
|
||||
otherWsClient = super.getAnotherWsClient();
|
||||
loginTenantAdmin();
|
||||
}
|
||||
|
||||
|
||||
@ -16,14 +16,22 @@
|
||||
package org.thingsboard.server.service.security.auth;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.NotificationCenter;
|
||||
import org.thingsboard.server.common.data.AdminSettings;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.SystemAdministratorsFilter;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
import org.thingsboard.server.common.data.security.model.JwtSettings;
|
||||
import org.thingsboard.server.common.data.security.model.JwtToken;
|
||||
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
||||
import org.thingsboard.server.service.security.auth.jwt.settings.DefaultJwtSettingsService;
|
||||
import org.thingsboard.server.service.security.auth.jwt.settings.DefaultJwtSettingsValidator;
|
||||
import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService;
|
||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||
import org.thingsboard.server.service.security.model.UserPrincipal;
|
||||
@ -33,28 +41,40 @@ import org.thingsboard.server.service.security.model.token.RawAccessJwtToken;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.willReturn;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class JwtTokenFactoryTest {
|
||||
|
||||
private static JwtTokenFactory tokenFactory;
|
||||
private static JwtSettings jwtSettings;
|
||||
private JwtTokenFactory tokenFactory;
|
||||
private AdminSettingsService adminSettingsService;
|
||||
private NotificationCenter notificationCenter;
|
||||
private JwtSettingsService jwtSettingsService;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeAll() {
|
||||
private JwtSettings jwtSettings;
|
||||
|
||||
@Before
|
||||
public void beforeEach() {
|
||||
jwtSettings = new JwtSettings();
|
||||
jwtSettings.setTokenIssuer("tb");
|
||||
jwtSettings.setTokenSigningKey("abewafaf");
|
||||
jwtSettings.setTokenExpirationTime((int) TimeUnit.HOURS.toSeconds(2));
|
||||
jwtSettings.setRefreshTokenExpTime((int) TimeUnit.DAYS.toSeconds(7));
|
||||
|
||||
JwtSettingsService jwtSettingsService = mock(JwtSettingsService.class);
|
||||
willReturn(jwtSettings).given(jwtSettingsService).getJwtSettings();
|
||||
adminSettingsService = mock(AdminSettingsService.class);
|
||||
notificationCenter = mock(NotificationCenter.class);
|
||||
jwtSettingsService = mockJwtSettingsService();
|
||||
mockJwtSettings(jwtSettings);
|
||||
|
||||
tokenFactory = new JwtTokenFactory(jwtSettingsService);
|
||||
}
|
||||
@ -150,6 +170,33 @@ public class JwtTokenFactoryTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJwtSigningKeyIssueNotification() {
|
||||
JwtSettings badJwtSettings = jwtSettings;
|
||||
badJwtSettings.setTokenSigningKey(JwtSettingsService.TOKEN_SIGNING_KEY_DEFAULT);
|
||||
mockJwtSettings(badJwtSettings);
|
||||
jwtSettingsService = mockJwtSettingsService();
|
||||
|
||||
for (int i = 0; i < 5; i++) { // to check if notification is not sent twice
|
||||
jwtSettingsService.getJwtSettings();
|
||||
}
|
||||
verify(notificationCenter, times(1)).sendGeneralWebNotification(eq(TenantId.SYS_TENANT_ID),
|
||||
isA(SystemAdministratorsFilter.class), argThat(template -> template.getConfiguration().getDeliveryMethodsTemplates().get(NotificationDeliveryMethod.WEB)
|
||||
.getBody().contains("The platform is configured to use default JWT Signing Key")));
|
||||
}
|
||||
|
||||
private void mockJwtSettings(JwtSettings settings) {
|
||||
AdminSettings adminJwtSettings = new AdminSettings();
|
||||
adminJwtSettings.setJsonValue(JacksonUtil.valueToTree(settings));
|
||||
when(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, JwtSettingsService.ADMIN_SETTINGS_JWT_KEY))
|
||||
.thenReturn(adminJwtSettings);
|
||||
}
|
||||
|
||||
private DefaultJwtSettingsService mockJwtSettingsService() {
|
||||
return new DefaultJwtSettingsService(adminSettingsService, Optional.empty(),
|
||||
Optional.of(notificationCenter), new DefaultJwtSettingsValidator());
|
||||
}
|
||||
|
||||
private void checkExpirationTime(JwtToken jwtToken, int tokenLifetime) {
|
||||
Claims claims = tokenFactory.parseTokenClaims(jwtToken).getBody();
|
||||
assertThat(claims.getExpiration()).matches(actualExpirationTime -> {
|
||||
|
||||
@ -66,6 +66,9 @@ import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
|
||||
@RequiredArgsConstructor
|
||||
public class DefaultNotifications {
|
||||
|
||||
private static final String YELLOW_COLOR = "#F9D916";
|
||||
private static final String RED_COLOR = "#e91a1a";
|
||||
|
||||
public static final DefaultNotification maintenanceWork = DefaultNotification.builder()
|
||||
.name("Maintenance work notification")
|
||||
.subject("Infrastructure maintenance")
|
||||
@ -77,7 +80,7 @@ public class DefaultNotifications {
|
||||
.type(NotificationType.ENTITIES_LIMIT)
|
||||
.subject("${entityType}s limit will be reached soon for tenant ${tenantName}")
|
||||
.text("${entityType}s usage: ${currentCount}/${limit} (${percents}%)")
|
||||
.icon("warning").color("#F9D916")
|
||||
.icon("warning").color(YELLOW_COLOR)
|
||||
.rule(DefaultRule.builder()
|
||||
.name("Entities count limit (sysadmin)")
|
||||
.triggerConfig(EntitiesLimitNotificationRuleTriggerConfig.builder()
|
||||
@ -100,7 +103,7 @@ public class DefaultNotifications {
|
||||
.type(NotificationType.API_USAGE_LIMIT)
|
||||
.subject("${feature} feature will be disabled soon for tenant ${tenantName}")
|
||||
.text("Usage: ${currentValue} out of ${limit} ${unitLabel}s")
|
||||
.icon("warning").color("#F9D916")
|
||||
.icon("warning").color(YELLOW_COLOR)
|
||||
.rule(DefaultRule.builder()
|
||||
.name("API feature warning (sysadmin)")
|
||||
.triggerConfig(ApiUsageLimitNotificationRuleTriggerConfig.builder()
|
||||
@ -123,7 +126,7 @@ public class DefaultNotifications {
|
||||
.type(NotificationType.API_USAGE_LIMIT)
|
||||
.subject("${feature} feature was disabled for tenant ${tenantName}")
|
||||
.text("Used ${currentValue} out of ${limit} ${unitLabel}s")
|
||||
.icon("block").color("#e91a1a")
|
||||
.icon("block").color(RED_COLOR)
|
||||
.rule(DefaultRule.builder()
|
||||
.name("API feature disabled (sysadmin)")
|
||||
.triggerConfig(ApiUsageLimitNotificationRuleTriggerConfig.builder()
|
||||
@ -147,7 +150,7 @@ public class DefaultNotifications {
|
||||
.type(NotificationType.RATE_LIMITS)
|
||||
.subject("Rate limits exceeded")
|
||||
.text("Rate limits for ${api} exceeded")
|
||||
.icon("block").color("#e91a1a")
|
||||
.icon("block").color(RED_COLOR)
|
||||
.rule(DefaultRule.builder()
|
||||
.name("Per-tenant rate limits exceeded")
|
||||
.triggerConfig(RateLimitsNotificationRuleTriggerConfig.builder()
|
||||
@ -164,7 +167,7 @@ public class DefaultNotifications {
|
||||
.type(NotificationType.RATE_LIMITS)
|
||||
.subject("Rate limits exceeded")
|
||||
.text("Rate limits for ${api} exceeded for '${limitLevelEntityName}'")
|
||||
.icon("block").color("#e91a1a")
|
||||
.icon("block").color(RED_COLOR)
|
||||
.rule(DefaultRule.builder()
|
||||
.name("Per-entity rate limits exceeded")
|
||||
.triggerConfig(RateLimitsNotificationRuleTriggerConfig.builder()
|
||||
@ -323,6 +326,15 @@ public class DefaultNotifications {
|
||||
.build())
|
||||
.build();
|
||||
|
||||
public static final DefaultNotification jwtSigningKeyIssue = DefaultNotification.builder()
|
||||
.name("JWT Signing Key issue notification")
|
||||
.type(NotificationType.GENERAL)
|
||||
.subject("WARNING: security issue")
|
||||
.text("The platform is configured to use default JWT Signing Key. Please change it on the security settings page")
|
||||
.icon("warning").color(YELLOW_COLOR)
|
||||
.button("Go to settings").link("/security-settings/general")
|
||||
.build();
|
||||
|
||||
private final NotificationTemplateService templateService;
|
||||
private final NotificationRuleService ruleService;
|
||||
|
||||
|
||||
@ -22,6 +22,8 @@ import org.thingsboard.server.common.data.id.UserId;
|
||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequest;
|
||||
import org.thingsboard.server.common.data.notification.NotificationRequestStats;
|
||||
import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter;
|
||||
import org.thingsboard.server.common.data.notification.template.NotificationTemplate;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
@ -30,6 +32,8 @@ public interface NotificationCenter {
|
||||
|
||||
NotificationRequest processNotificationRequest(TenantId tenantId, NotificationRequest notificationRequest, Consumer<NotificationRequestStats> callback);
|
||||
|
||||
void sendGeneralWebNotification(TenantId tenantId, UsersFilter recipients, NotificationTemplate template);
|
||||
|
||||
void deleteNotificationRequest(TenantId tenantId, NotificationRequestId notificationRequestId);
|
||||
|
||||
void markNotificationAsRead(TenantId tenantId, UserId recipientId, NotificationId notificationId);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user