Skip to content

Commit

Permalink
AM-87 Update the certificate used by applications after a default cer…
Browse files Browse the repository at this point in the history
…t renewal
  • Loading branch information
leleueri authored and ashraf706 committed Nov 21, 2022
1 parent d51bda9 commit 979e7b6
Show file tree
Hide file tree
Showing 28 changed files with 1,170 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
* @author GraviteeSource Team
*/
public interface ConstantKeys {

// Common key.
String CLIENT_CONTEXT_KEY = "client";
String USER_CONTEXT_KEY = "user";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import io.gravitee.plugin.alert.AlertEventProducerManager;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* 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 io.gravitee.am.management.service.tasks;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.gravitee.am.repository.management.api.CertificateRepository;
import io.gravitee.am.repository.management.api.SystemTaskRepository;
import io.gravitee.am.service.ApplicationService;
import io.gravitee.am.service.TaskManager;
import io.gravitee.am.service.tasks.AssignSystemCertificate;
import io.gravitee.am.service.tasks.AssignSystemCertificateDefinition;
import io.gravitee.am.service.tasks.TaskType;
import io.gravitee.common.component.LifecycleComponent;
import io.gravitee.common.service.AbstractService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Component;

/**
* This class is used to read tasks from the SystemTask that may be scheduled.
* The goal is to ensure that scheduled task are executed if the Management instance
* restart before the task execution.
*
* @author Eric LELEU (eric.leleu at graviteesource.com)
* @author GraviteeSource Team
*/
@Component
public class TasksLoader extends AbstractService<TasksLoader> implements LifecycleComponent<TasksLoader> {

private final Logger logger = LoggerFactory.getLogger(TaskManager.class);

@Autowired
private ObjectMapper mapper;
@Autowired
private TaskScheduler scheduler;
@Autowired
@Lazy
private SystemTaskRepository taskRepository;
@Autowired
@Lazy
private ApplicationService applicationService;
@Autowired
@Lazy
private CertificateRepository certificateRepository;
@Autowired
private TaskManager taskManager;

@Override
protected void doStart() throws Exception {
super.doStart();
this.logger.info("Load scheduled tasks");
this.taskRepository.findByType(TaskType.SIMPLE.name())
// currently only one kind of Simple tasks, so we simply filter on this value for safety
.filter(systemTask -> AssignSystemCertificate.class.getSimpleName().equals(systemTask.getKind()))
.map(systemTask -> {
final var assignSystemCert = new AssignSystemCertificate(systemTask.getId(), this.applicationService, this.certificateRepository, this.taskManager);
final var taskConfiguration = mapper.readValue(systemTask.getConfiguration(), AssignSystemCertificateDefinition.class);
assignSystemCert.setDefinition(taskConfiguration);
return assignSystemCert;
})
.subscribe(task -> {
logger.debug("Reschedule {} task of type {} with definition {}", task.type(), task.kind(), task.getDefinition());
task.registerScheduler(this.scheduler);
task.schedule();
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* 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 io.gravitee.am.management.service.tasks;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.gravitee.am.model.SystemTask;
import io.gravitee.am.repository.management.api.SystemTaskRepository;
import io.gravitee.am.service.tasks.AssignSystemCertificate;
import io.gravitee.am.service.tasks.TaskType;
import io.reactivex.Flowable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.scheduling.TaskScheduler;

import javax.annotation.OverridingMethodsMustInvokeSuper;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.Random;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyChar;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static reactor.core.publisher.Mono.when;

/**
* @author Eric LELEU (eric.leleu at graviteesource.com)
* @author GraviteeSource Team
*/
@RunWith(MockitoJUnitRunner.class)
public class TasksLoaderTest {

@InjectMocks
private TasksLoader tasksLoader;

@Mock
private SystemTaskRepository taskRepository;

@Mock
private TaskScheduler scheduler;

@Spy
private ObjectMapper mapper = new ObjectMapper();

@Test
public void shouldSchedule_SimpleTask() throws Exception {
var tasks = new ArrayList<>();
final int numberOfSimpleTasks = new Random().nextInt(10);
for (int i = 0; i < numberOfSimpleTasks; ++i) {
var task = new SystemTask();
task.setId("simple-task-"+i);
task.setType(TaskType.SIMPLE.name());
task.setKind(AssignSystemCertificate.class.getSimpleName());
task.setConfiguration("{\"delay\": 1 , \"unit\": \"MINUTES\"}");
tasks.add(task);
}

final int numberOfOtherTasks = new Random().nextInt(10);
for (int i = 0; i < numberOfOtherTasks; ++i) {
var task = new SystemTask();
task.setId("other-task-"+i);
task.setType(TaskType.SIMPLE.name());
task.setKind("other");
tasks.add(task);
}

doReturn(Flowable.fromIterable(tasks)).when(taskRepository).findByType(TaskType.SIMPLE.name());

tasksLoader.doStart();

verify(scheduler, times(numberOfSimpleTasks)).schedule(argThat(task -> task instanceof AssignSystemCertificate), any(Instant.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
*/
package io.gravitee.am.management.standalone.node;

import io.gravitee.am.management.service.*;
import io.gravitee.am.management.service.AlertTriggerManager;
import io.gravitee.am.management.service.AuditReporterManager;
import io.gravitee.am.management.service.CertificateManager;
import io.gravitee.am.management.service.EmailManager;
import io.gravitee.am.management.service.IdentityProviderManager;
import io.gravitee.am.management.service.InitializerService;
import io.gravitee.am.management.service.tasks.TasksLoader;
import io.gravitee.common.component.LifecycleComponent;
import io.gravitee.node.api.NodeMetadataResolver;
import io.gravitee.node.jetty.node.JettyNode;
Expand Down Expand Up @@ -70,6 +76,7 @@ public List<Class<? extends LifecycleComponent>> components() {
components.add(AlertTriggerManager.class);
components.add(AlertTriggerProviderManager.class);
components.add(AlertEventProducerManager.class);
components.add(TasksLoader.class);

return components;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ domains:
validity: 365 # Validity of the certificate
algorithm: SHA256withRSA # Algorithm used to sign certificate
name: cn=Gravitee.io # Certificate X.500 name
## Refresh section is used to define the delay between a system certificate renewal
## and the applications update to use this new certificate
# refresh:
# delay: 10
# timeUnit: MINUTES

# JWT used to generate signed token for management security mechanism (Bearer Token) and to verify emails
jwt:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@ public class SystemTask {

private String id;
private String type;
private String kind;
private String status;
private String operationId;
private Date createdAt;
private Date updatedAt;

private String configuration;

public String getId() {
return id;
}
Expand All @@ -46,6 +49,14 @@ public void setType(String type) {
this.type = type;
}

public String getKind() {
return kind;
}

public void setKind(String kind) {
this.kind = kind;
}

public String getStatus() {
return status;
}
Expand Down Expand Up @@ -77,4 +88,12 @@ public String getOperationId() {
public void setOperationId(String operationId) {
this.operationId = operationId;
}

public String getConfiguration() {
return configuration;
}

public void setConfiguration(String configuration) {
this.configuration = configuration;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import io.gravitee.am.model.SystemTask;
import io.gravitee.am.repository.common.CrudRepository;
import io.reactivex.Flowable;
import io.reactivex.Single;

/**
Expand All @@ -26,4 +27,6 @@
public interface SystemTaskRepository extends CrudRepository<SystemTask, String> {

Single<SystemTask> updateIf(SystemTask item, String operationId);

Flowable<SystemTask> findByType(String type);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.gravitee.am.repository.jdbc.management.api.model.mapper.LocalDateConverter;
import io.gravitee.am.repository.management.api.SystemTaskRepository;
import io.reactivex.Completable;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import io.reactivex.Single;
import org.springframework.beans.factory.InitializingBean;
Expand Down Expand Up @@ -49,6 +50,8 @@ public class JdbcSystemTaskRepository extends AbstractJdbcRepository implements
public static final String COL_OPERATION_ID = "operation_id";
public static final String COL_CREATED_AT = "created_at";
public static final String COL_UPDATED_AT = "updated_at";
public static final String COL_CONFIGURATION = "configuration";
public static final String COL_KIND = "kind";
public static final String WHERE_SUFFIX = "_where";

private static final List<String> columns = List.of(
Expand All @@ -57,7 +60,9 @@ public class JdbcSystemTaskRepository extends AbstractJdbcRepository implements
COL_STATUS,
COL_OPERATION_ID,
COL_CREATED_AT,
COL_UPDATED_AT
COL_UPDATED_AT,
COL_CONFIGURATION,
COL_KIND
);

private String INSERT_STATEMENT;
Expand Down Expand Up @@ -99,6 +104,8 @@ public Single<SystemTask> create(SystemTask item) {
insertSpec = addQuotedField(insertSpec, COL_OPERATION_ID, item.getOperationId(), String.class);
insertSpec = addQuotedField(insertSpec, COL_CREATED_AT, dateConverter.convertTo(item.getCreatedAt(), null), LocalDateTime.class);
insertSpec = addQuotedField(insertSpec, COL_UPDATED_AT, dateConverter.convertTo(item.getUpdatedAt(), null), LocalDateTime.class);
insertSpec = addQuotedField(insertSpec, COL_CONFIGURATION, item.getConfiguration(), String.class);
insertSpec = addQuotedField(insertSpec, COL_KIND, item.getKind(), String.class);

Mono<Integer> action = insertSpec.fetch().rowsUpdated();
return monoToSingle(action).flatMap((i) -> this.findById(item.getId()).toSingle());
Expand All @@ -121,6 +128,8 @@ public Single<SystemTask> updateIf(SystemTask item, String operationId) {
updateSpec = addQuotedField(updateSpec, COL_OPERATION_ID, item.getOperationId(), String.class);
updateSpec = addQuotedField(updateSpec, COL_CREATED_AT, dateConverter.convertTo(item.getCreatedAt(), null), LocalDateTime.class);
updateSpec = addQuotedField(updateSpec, COL_UPDATED_AT, dateConverter.convertTo(item.getUpdatedAt(), null), LocalDateTime.class);
updateSpec = addQuotedField(updateSpec, COL_CONFIGURATION, item.getConfiguration(), String.class);
updateSpec = addQuotedField(updateSpec, COL_KIND, item.getKind(), String.class);
updateSpec = addQuotedField(updateSpec, COL_OPERATION_ID + WHERE_SUFFIX, operationId, String.class);

Mono<Integer> action = updateSpec.fetch().rowsUpdated();
Expand All @@ -134,4 +143,10 @@ public Completable delete(String id) {
.matching(Query.query(where(COL_ID).is(id))).all();
return monoToCompletable(delete);
}

@Override
public Flowable<SystemTask> findByType(String type) {
return fluxToFlowable(template.select(Query.query(where(COL_TYPE).is(type)), JdbcSystemTask.class))
.map(this::toEntity);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class JdbcSystemTask {
@Column("updated_at")
private LocalDateTime updatedAt;

private String configuration;
public String getId() {
return id;
}
Expand Down Expand Up @@ -85,4 +86,12 @@ public String getOperationId() {
public void setOperationId(String operationId) {
this.operationId = operationId;
}

public String getConfiguration() {
return configuration;
}

public void setConfiguration(String configuration) {
this.configuration = configuration;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
databaseChangeLog:
- changeSet:
id: 3.20.0-update-system-tasks-table
author: GraviteeSource Team
changes:
## system task table
#####################
- addColumn:
tableName: system_tasks
columns:
- column: { name: configuration, type: clob, constraints: { nullable: true } }
- column: { name: kind, type: varchar(128), constraints: { nullable: true } }
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,6 @@ databaseChangeLog:
- file: liquibase/changelogs/v3_20_0/3.20.0-update-certificates-table.yml
- include:
- file: liquibase/changelogs/v3_20_0/3.20.0-add-rate-limit-table.yml
- include:
- file: liquibase/changelogs/v3_20_0/3.20.0-update-system-tasks-table.yml

Loading

0 comments on commit 979e7b6

Please sign in to comment.