Pull request #673: RED-3800 fix permissions

Merge in RED/persistence-service from RED-3800-fix-permissions to master

* commit '4b941397df3d4de38923569ac983f0c35d9276dd':
  RED-3800 - sync custom permissions and KC users based on CRON and do it more often
This commit is contained in:
Timo Bejan 2023-04-24 09:18:34 +02:00
commit 534efa138d
5 changed files with 111 additions and 13 deletions

View File

@ -1,8 +1,15 @@
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
import java.time.OffsetDateTime;
import java.util.Map;
import java.util.stream.Collectors;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
@ -23,11 +30,22 @@ import com.iqser.red.service.persistence.management.v1.processor.exception.BadRe
import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.job.AutomaticAnalysisJob;
import com.iqser.red.service.persistence.management.v1.processor.service.job.SyncUserPermissionsJob;
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequiredArgsConstructor
@RestControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ExternalControllerAdvice {
private final Scheduler scheduler;
@ResponseBody
@ResponseStatus(value = HttpStatus.NOT_FOUND)
@ExceptionHandler(value = NotFoundException.class)
@ -76,6 +94,22 @@ public class ExternalControllerAdvice {
}
@ResponseBody
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler({org.springframework.security.acls.model.NotFoundException.class})
public ErrorMessage handleACLNotFound(org.springframework.security.acls.model.NotFoundException e) {
// in case this error occurs on a rest request / force trigger the sync job
try {
scheduler.triggerJob(new JobKey("SyncUserPermissionsJob"), new JobDataMap(Map.of("tenantId", TenantContext.getTenantId())));
} catch (SchedulerException ex) {
log.debug("Failed to force trigger SyncUserPermissionsJob", ex);
}
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
}
@ResponseBody
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ExceptionHandler({MethodArgumentNotValidException.class})

View File

@ -14,7 +14,9 @@ import org.springframework.context.annotation.Configuration;
import com.iqser.red.service.persistence.management.v1.processor.service.job.AutomaticAnalysisJob;
import com.iqser.red.service.persistence.management.v1.processor.service.job.DeletedFilesCleanupJob;
import com.iqser.red.service.persistence.management.v1.processor.service.job.DownloadCleanupJob;
import com.iqser.red.service.persistence.management.v1.processor.service.job.KeyCloakUserSyncJob;
import com.iqser.red.service.persistence.management.v1.processor.service.job.SendNotificationEmailJob;
import com.iqser.red.service.persistence.management.v1.processor.service.job.SyncUserPermissionsJob;
@Configuration
public class CreateJobsConfiguration {
@ -91,6 +93,54 @@ public class CreateJobsConfiguration {
}
@Bean
public Trigger keyCloakUserSyncJobTrigger() throws ParseException {
return TriggerBuilder.newTrigger()
.forJob(keyCloakUserSyncJobDetail())
.withIdentity("KeyCloakUserSyncJobTrigger")
.withDescription("Triggers KeyCloakUserSyncJob every 2 minutes")
.withSchedule(CronScheduleBuilder.cronSchedule(new CronExpression("0 */2 * * * ?")))
.build();
}
@Bean
public JobDetail keyCloakUserSyncJobDetail() {
return JobBuilder.newJob()
.ofType(KeyCloakUserSyncJob.class)
.storeDurably()
.withIdentity("KeyCloakUserSyncJob")
.withDescription("Sync KC Users in case of deletions in KC")
.build();
}
@Bean
public Trigger syncUserPermissionsJobTrigger() throws ParseException {
return TriggerBuilder.newTrigger()
.forJob(syncUserPermissionsJobDetail())
.withIdentity("SyncUserPermissionsJobTrigger")
.withDescription("Triggers SyncUserPermissionsJob every 2 minutes")
.withSchedule(CronScheduleBuilder.cronSchedule(new CronExpression("0 */2 * * * ?")))
.build();
}
@Bean
public JobDetail syncUserPermissionsJobDetail() {
return JobBuilder.newJob()
.ofType(SyncUserPermissionsJob.class)
.storeDurably()
.withIdentity("SyncUserPermissionsJob")
.withDescription("Sync custom permissions for ACL")
.build();
}
@Bean
public Trigger downloadCleanupJobTrigger() throws ParseException {

View File

@ -1,21 +1,26 @@
package com.iqser.red.service.persistence.management.v1.processor.job;
package com.iqser.red.service.persistence.management.v1.processor.service.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.job.KeyCloakUserSyncService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
@RequiredArgsConstructor
public class KeyCloakUserSyncJob {
public class KeyCloakUserSyncJob implements Job {
private final KeyCloakUserSyncService keyCloakUserSyncService;
@Scheduled(fixedRate = 1000 * 60, initialDelay = 1000 * 60)
public void syncCustomPermissions() {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
keyCloakUserSyncService.syncUsersWithKC();
}

View File

@ -1,5 +1,8 @@
package com.iqser.red.service.persistence.management.v1.processor.acl.custom.job;
package com.iqser.red.service.persistence.management.v1.processor.service.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@ -13,18 +16,24 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
@RequiredArgsConstructor
public class SyncUserPermissionsJob {
public class SyncUserPermissionsJob implements Job {
private final CustomPermissionService customPermissionService;
private final TenantManagementService tenantManagementService;
@Scheduled(fixedRate = 1000 * 60 * 10, initialDelay = 1000 * 60)
public void syncCustomPermissions() {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
var singleTenant = context.getJobDetail().getJobDataMap() != null ? context.getJobDetail().getJobDataMap().get("tenantId") : null;
tenantManagementService.getTenants().forEach(tenant -> {
TenantContext.setTenantId(tenant.getTenantId());
customPermissionService.syncAllCustomPermissions();
// if it's for a single tenant run only for that one, else run it for all tenants
if (tenant.getTenantId().equals(singleTenant) || singleTenant == null) {
TenantContext.setTenantId(tenant.getTenantId());
customPermissionService.syncAllCustomPermissions();
TenantContext.clear();
}
});
}

View File

@ -97,8 +97,8 @@ multitenancy:
password: ${PSQL_PASSWORD:redaction}
platform: org.hibernate.dialect.PostgreSQL95Dialect
hikari:
maximumPoolSize: 5
minimum-idle: 5
maximumPoolSize: 2
minimum-idle: 2
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 1000
@ -109,7 +109,7 @@ multitenancy:
datasource:
driverClassName: org.postgresql.Driver
hikari:
maximumPoolSize: 5
maximumPoolSize: 8
minimum-idle: 5
data-source-properties:
cachePrepStmts: true