diff --git a/openaev-api/src/main/java/io/openaev/migration/V4_74__Create_default_tenant.java b/openaev-api/src/main/java/io/openaev/migration/V4_74__Create_default_tenant.java new file mode 100644 index 00000000000..cf5156d977d --- /dev/null +++ b/openaev-api/src/main/java/io/openaev/migration/V4_74__Create_default_tenant.java @@ -0,0 +1,95 @@ +package io.openaev.migration; + +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; + +import java.sql.Statement; +import java.util.List; +import org.flywaydb.core.api.migration.BaseJavaMigration; +import org.flywaydb.core.api.migration.Context; +import org.springframework.stereotype.Component; + +@Component +public class V4_74__Create_default_tenant extends BaseJavaMigration { + + // Strings to replace in the SQL statement + private static List TABLES = + List.of( + "agents", + "asset_agent_jobs", + "asset_groups", + "assets", + "attack_patterns", + "challenges", + "channels", + "collectors", + "connector_instances", + "custom_dashboards", + "datapacks", + "documents", + "executors", + "exercises", + "findings", + "groups", + "import_mappers", + "injectors", + "injects", + "kill_chain_phases", + "lessons_templates", + "mitigations", + "organizations", + "notification_rules", + "payloads", + "roles", + "scenarios", + "tag_rules", + "tags", + "teams", + "vulnerabilities"); + + @Override + public void migrate(Context context) throws Exception { + try (Statement statement = context.getConnection().createStatement()) { + // Add default tenant + statement.execute( + String.format( + """ + INSERT INTO tenants(tenant_id, tenant_name, tenant_description) + VALUES ('%s', 'First default tenant auto created to rename', 'First default tenant auto created to rename'); + """, + DEFAULT_TENANT_UUID)); + // Add deleted_at in tenants for soft delete + statement.execute("ALTER TABLE tenants ADD tenant_deleted_at TIMESTAMP WITH TIME ZONE;"); + // Add foreign keys with index, auto set default tenant id with default value + for (String table : TABLES) { + statement.addBatch( + String.format( + """ + ALTER TABLE %s + ADD COLUMN tenant_id VARCHAR(255) NOT NULL DEFAULT '%s', + ADD CONSTRAINT fk_tenant_id FOREIGN KEY (tenant_id) REFERENCES tenants(tenant_id) ON DELETE CASCADE; + """, + table, DEFAULT_TENANT_UUID)); + statement.addBatch( + String.format( + """ + CREATE INDEX IF NOT EXISTS idx_tenant_id ON %s(tenant_id); + """, + table)); + } + statement.executeBatch(); + // Add linked table for users and tenants + statement.execute( + """ + CREATE TABLE IF NOT EXISTS users_tenants ( + user_id VARCHAR(255) NOT NULL, + tenant_id VARCHAR(255) NOT NULL, + PRIMARY KEY (user_id, tenant_id), + CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE, + CONSTRAINT fk_tenant_id FOREIGN KEY (tenant_id) REFERENCES tenants(tenant_id) ON DELETE CASCADE + ); + """); + statement.execute("CREATE INDEX IF NOT EXISTS idx_user_id ON users_tenants(user_id);"); + statement.execute("CREATE INDEX IF NOT EXISTS idx_tenant_id ON users_tenants(tenant_id);"); + } + } +} diff --git a/openaev-model/src/main/java/io/openaev/context/TenantContext.java b/openaev-model/src/main/java/io/openaev/context/TenantContext.java new file mode 100644 index 00000000000..3d7acd5eb76 --- /dev/null +++ b/openaev-model/src/main/java/io/openaev/context/TenantContext.java @@ -0,0 +1,18 @@ +package io.openaev.context; + +import io.openaev.database.model.Tenant; + +public class TenantContext { + + private static final ThreadLocal CURRENT_TENANT = new ThreadLocal<>(); + + public static String getCurrentTenant() { + return Tenant.DEFAULT_TENANT_UUID; + // return CURRENT_TENANT.get(); + } + + // TODO multi-tenancy: set with Front URL instead of default UUID and update the return above + public static void setCurrentTenant(String tenant) { + CURRENT_TENANT.set(tenant); + } +} diff --git a/openaev-model/src/main/java/io/openaev/database/model/Agent.java b/openaev-model/src/main/java/io/openaev/database/model/Agent.java index 33a933f162e..37b3271c29f 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Agent.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Agent.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -144,6 +145,13 @@ public boolean isActive() { @Transient private final ResourceType resourceType = ResourceType.AGENT; + // Ignore json and not null + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Override public int hashCode() { return Objects.hash(id); diff --git a/openaev-model/src/main/java/io/openaev/database/model/Asset.java b/openaev-model/src/main/java/io/openaev/database/model/Asset.java index ea7b33c839a..5ff0ebcb521 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Asset.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Asset.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static jakarta.persistence.DiscriminatorType.STRING; import static java.time.Instant.now; import static lombok.AccessLevel.NONE; @@ -63,6 +64,12 @@ public class Asset implements Base { @JsonProperty("asset_external_reference") private String externalReference; + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + // -- TAG -- @Schema(implementation = String[].class) diff --git a/openaev-model/src/main/java/io/openaev/database/model/AssetAgentJob.java b/openaev-model/src/main/java/io/openaev/database/model/AssetAgentJob.java index c3dd007301a..efe11e8708b 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/AssetAgentJob.java +++ b/openaev-model/src/main/java/io/openaev/database/model/AssetAgentJob.java @@ -1,5 +1,8 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; + +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openaev.database.audit.ModelBaseListener; @@ -7,6 +10,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import java.util.Objects; import lombok.Data; import lombok.Getter; @@ -48,6 +52,12 @@ public class AssetAgentJob implements Base { @NotBlank private String command; + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Override public String toString() { return id; diff --git a/openaev-model/src/main/java/io/openaev/database/model/AssetGroup.java b/openaev-model/src/main/java/io/openaev/database/model/AssetGroup.java index fea2dd0a36e..de86b67bd1f 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/AssetGroup.java +++ b/openaev-model/src/main/java/io/openaev/database/model/AssetGroup.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import static lombok.AccessLevel.NONE; @@ -57,6 +58,12 @@ public class AssetGroup implements Base { @JsonProperty("asset_group_external_reference") private String externalReference; + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + // -- ASSET -- @Type(JsonType.class) diff --git a/openaev-model/src/main/java/io/openaev/database/model/AttackPattern.java b/openaev-model/src/main/java/io/openaev/database/model/AttackPattern.java index 22e29f91557..9ab74d4e507 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/AttackPattern.java +++ b/openaev-model/src/main/java/io/openaev/database/model/AttackPattern.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -14,6 +15,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -101,6 +103,12 @@ public class AttackPattern implements Base { @JsonProperty("attack_pattern_kill_chain_phases") private List killChainPhases = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Getter(onMethod_ = @JsonIgnore) @Transient private final ResourceType resourceType = ResourceType.ATTACK_PATTERN; diff --git a/openaev-model/src/main/java/io/openaev/database/model/Challenge.java b/openaev-model/src/main/java/io/openaev/database/model/Challenge.java index fe2c66d1fa5..ad21e27a0fa 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Challenge.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Challenge.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -97,6 +98,12 @@ public class Challenge implements Base { @JsonProperty("challenge_documents") private List documents = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Transient private List exerciseIds = new ArrayList<>(); @Transient private List scenarioIds = new ArrayList<>(); diff --git a/openaev-model/src/main/java/io/openaev/database/model/Channel.java b/openaev-model/src/main/java/io/openaev/database/model/Channel.java index df2dcf2454b..a32ea429565 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Channel.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Channel.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -90,6 +91,12 @@ public class Channel implements Base { @Schema(implementation = String.class) private Document logoLight; + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Getter(onMethod_ = @JsonIgnore) @Transient private final ResourceType resourceType = ResourceType.CHANNEL; diff --git a/openaev-model/src/main/java/io/openaev/database/model/Collector.java b/openaev-model/src/main/java/io/openaev/database/model/Collector.java index 89a9ba64539..c8d89933d91 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Collector.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Collector.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -71,6 +72,12 @@ public class Collector extends BaseConnectorEntity { @Type(JsonType.class) private ObjectNode state; + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Getter(onMethod_ = @JsonIgnore) @Transient private final ResourceType resourceType = ResourceType.COLLECTOR; diff --git a/openaev-model/src/main/java/io/openaev/database/model/ConnectorInstancePersisted.java b/openaev-model/src/main/java/io/openaev/database/model/ConnectorInstancePersisted.java index 08e82763a33..6d4750529b8 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/ConnectorInstancePersisted.java +++ b/openaev-model/src/main/java/io/openaev/database/model/ConnectorInstancePersisted.java @@ -1,6 +1,9 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; + import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.openaev.database.audit.ModelBaseListener; import jakarta.persistence.*; @@ -90,6 +93,12 @@ public class ConnectorInstancePersisted extends ConnectorInstance implements Bas @NotNull private Set configurations = new HashSet<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Override public String getClassName() { if (this.getCatalogConnector() != null) { diff --git a/openaev-model/src/main/java/io/openaev/database/model/CustomDashboard.java b/openaev-model/src/main/java/io/openaev/database/model/CustomDashboard.java index 3bbd0b7981d..29e411b331e 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/CustomDashboard.java +++ b/openaev-model/src/main/java/io/openaev/database/model/CustomDashboard.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static jakarta.persistence.FetchType.LAZY; import static java.time.Instant.now; import static java.util.function.Function.identity; @@ -68,6 +69,12 @@ public class CustomDashboard implements Base { @OrderBy("id ASC") private List parameters = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + public CustomDashboard addParameter( @NotBlank final String name, @NotBlank final CustomDashboardParameterType type) { if (this.getParameters().stream().anyMatch(p -> p.getType().equals(type) && type.uniq)) { diff --git a/openaev-model/src/main/java/io/openaev/database/model/DataPack.java b/openaev-model/src/main/java/io/openaev/database/model/DataPack.java index 1089426247a..0a6b248bc87 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/DataPack.java +++ b/openaev-model/src/main/java/io/openaev/database/model/DataPack.java @@ -1,8 +1,12 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; + +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.Setter; @@ -16,4 +20,10 @@ public class DataPack { @JsonProperty("datapack_id") @NotBlank private String id; + + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); } diff --git a/openaev-model/src/main/java/io/openaev/database/model/Document.java b/openaev-model/src/main/java/io/openaev/database/model/Document.java index e8ffc002890..21fedd08b3a 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Document.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Document.java @@ -1,5 +1,7 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -9,6 +11,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import java.util.HashSet; import java.util.Objects; import java.util.Set; @@ -108,6 +111,12 @@ public class Document implements Base { @JsonIgnore private Set challenges = new HashSet<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @OneToMany(mappedBy = "document", fetch = FetchType.LAZY) @JsonIgnore private Set injectDocuments = new HashSet<>(); diff --git a/openaev-model/src/main/java/io/openaev/database/model/Executor.java b/openaev-model/src/main/java/io/openaev/database/model/Executor.java index 44ed4f9e4f6..b299f46ccf4 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Executor.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Executor.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -51,6 +52,12 @@ public class Executor extends BaseConnectorEntity { @JsonProperty("executor_background_color") private String backgroundColor; + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Column(name = "executor_created_at") @JsonProperty("executor_created_at") @NotNull diff --git a/openaev-model/src/main/java/io/openaev/database/model/Exercise.java b/openaev-model/src/main/java/io/openaev/database/model/Exercise.java index ec90cb59541..9416fee6c60 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Exercise.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Exercise.java @@ -2,6 +2,7 @@ import static io.openaev.database.model.Grant.GRANT_TYPE.OBSERVER; import static io.openaev.database.model.Grant.GRANT_TYPE.PLANNER; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static io.openaev.helper.UserHelper.getUsersByType; import static java.time.Instant.now; import static java.util.Optional.ofNullable; @@ -158,6 +159,12 @@ public class Exercise implements GrantableBase { @JsonProperty("exercise_lessons_anonymized") private boolean lessonsAnonymized = false; + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + // -- SCENARIO -- @Getter diff --git a/openaev-model/src/main/java/io/openaev/database/model/Finding.java b/openaev-model/src/main/java/io/openaev/database/model/Finding.java index efa91885936..3816657d488 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Finding.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Finding.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -80,6 +81,12 @@ public class Finding implements Base { @Queryable(filterable = true, dynamicValues = true, path = "tags.id") private Set tags = new HashSet<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + // -- RELATION -- @ManyToOne(fetch = FetchType.LAZY) diff --git a/openaev-model/src/main/java/io/openaev/database/model/Group.java b/openaev-model/src/main/java/io/openaev/database/model/Group.java index a855dc61155..80828d1f4a8 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Group.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Group.java @@ -1,5 +1,7 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -11,6 +13,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import java.util.*; import lombok.Getter; import lombok.Setter; @@ -77,6 +80,12 @@ public class Group implements Base { @JsonProperty("group_roles") private List roles = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Getter(onMethod_ = @JsonIgnore) @Transient private final ResourceType resourceType = ResourceType.USER_GROUP; diff --git a/openaev-model/src/main/java/io/openaev/database/model/ImportMapper.java b/openaev-model/src/main/java/io/openaev/database/model/ImportMapper.java index 7657e767f5d..f05863d3f89 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/ImportMapper.java +++ b/openaev-model/src/main/java/io/openaev/database/model/ImportMapper.java @@ -1,5 +1,8 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; + +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.openaev.annotation.Queryable; import io.openaev.database.audit.ModelBaseListener; @@ -46,6 +49,12 @@ public class ImportMapper implements Base { @JsonProperty("import_mapper_inject_importers") private List injectImporters = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @CreationTimestamp @Column(name = "mapper_created_at") @JsonProperty("import_mapper_created_at") diff --git a/openaev-model/src/main/java/io/openaev/database/model/Inject.java b/openaev-model/src/main/java/io/openaev/database/model/Inject.java index 9361c1b5000..7e25275ec34 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Inject.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Inject.java @@ -1,6 +1,7 @@ package io.openaev.database.model; import static io.openaev.database.model.CollectExecutionStatus.COLLECTING; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static io.openaev.database.specification.InjectSpecification.VALID_TESTABLE_TYPES; import static java.time.Instant.now; import static java.util.Optional.ofNullable; @@ -307,6 +308,12 @@ public void setAssetGroups(List assetGroups) { @OneToMany(mappedBy = "inject", cascade = CascadeType.ALL, orphanRemoval = true) private List findings = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Getter @Setter @Transient private boolean isListened = true; @Getter(onMethod_ = @JsonIgnore) diff --git a/openaev-model/src/main/java/io/openaev/database/model/Injector.java b/openaev-model/src/main/java/io/openaev/database/model/Injector.java index ce2bb4baf60..2ab245fb756 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Injector.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Injector.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -87,6 +88,12 @@ public class Injector extends BaseConnectorEntity { @JsonIgnore private List contracts = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Getter(onMethod_ = @JsonIgnore) @Transient private final ResourceType resourceType = ResourceType.INJECTOR; diff --git a/openaev-model/src/main/java/io/openaev/database/model/KillChainPhase.java b/openaev-model/src/main/java/io/openaev/database/model/KillChainPhase.java index 27a080f1ceb..8e9472e6898 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/KillChainPhase.java +++ b/openaev-model/src/main/java/io/openaev/database/model/KillChainPhase.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -78,6 +79,12 @@ public class KillChainPhase implements Base { @NotNull private Instant updatedAt = now(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Getter(onMethod_ = @JsonIgnore) @Transient private final ResourceType resourceType = ResourceType.KILL_CHAIN_PHASE; diff --git a/openaev-model/src/main/java/io/openaev/database/model/LessonsTemplate.java b/openaev-model/src/main/java/io/openaev/database/model/LessonsTemplate.java index da70eb8c783..269e61357d3 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/LessonsTemplate.java +++ b/openaev-model/src/main/java/io/openaev/database/model/LessonsTemplate.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -55,6 +56,12 @@ public class LessonsTemplate implements Base { @JsonIgnore private List categories = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Override public boolean isUserHasAccess(User user) { return user.isAdmin(); diff --git a/openaev-model/src/main/java/io/openaev/database/model/Mitigation.java b/openaev-model/src/main/java/io/openaev/database/model/Mitigation.java index 214a2133b5b..72e592b5870 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Mitigation.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Mitigation.java @@ -1,7 +1,9 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.hypersistence.utils.hibernate.type.array.StringArrayType; @@ -85,4 +87,10 @@ public class Mitigation implements Base { @JsonSerialize(using = MultiIdListSerializer.class) @JsonProperty("mitigation_attack_patterns") private List attackPatterns = new ArrayList<>(); + + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); } diff --git a/openaev-model/src/main/java/io/openaev/database/model/NotificationRule.java b/openaev-model/src/main/java/io/openaev/database/model/NotificationRule.java index 222fec9b1e6..88eb9f3c8f5 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/NotificationRule.java +++ b/openaev-model/src/main/java/io/openaev/database/model/NotificationRule.java @@ -1,5 +1,7 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.openaev.annotation.Queryable; @@ -62,6 +64,12 @@ public class NotificationRule implements Base { @Queryable(searchable = true, filterable = true, path = "owner.id") private User owner; + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Getter(onMethod_ = @JsonIgnore) @Transient private final ResourceType resourceType = ResourceType.NOTIFICATION_RULE; diff --git a/openaev-model/src/main/java/io/openaev/database/model/Organization.java b/openaev-model/src/main/java/io/openaev/database/model/Organization.java index 646dc524777..132ac8124a7 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Organization.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Organization.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import static java.util.stream.StreamSupport.stream; @@ -75,6 +76,12 @@ public class Organization implements Base { @JsonProperty("organization_tags") private Set tags = new HashSet<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + // region transient private transient List injects = new ArrayList<>(); diff --git a/openaev-model/src/main/java/io/openaev/database/model/Payload.java b/openaev-model/src/main/java/io/openaev/database/model/Payload.java index 3aa474325d5..a0cb8a5bc97 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Payload.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Payload.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static jakarta.persistence.DiscriminatorType.STRING; import static java.time.Instant.now; import static lombok.AccessLevel.NONE; @@ -191,6 +192,12 @@ public enum PAYLOAD_EXECUTION_ARCH { @NotNull private PAYLOAD_EXECUTION_ARCH executionArch = Payload.PAYLOAD_EXECUTION_ARCH.ALL_ARCHITECTURES; + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + // -- COLLECTOR -- @ManyToOne(fetch = FetchType.LAZY) diff --git a/openaev-model/src/main/java/io/openaev/database/model/Role.java b/openaev-model/src/main/java/io/openaev/database/model/Role.java index 07d1f908c26..b720db44584 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Role.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Role.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -66,4 +67,10 @@ public class Role implements Base { @NotNull @Schema(description = "Update date of the role", accessMode = Schema.AccessMode.READ_ONLY) private Instant updatedAt = now(); + + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); } diff --git a/openaev-model/src/main/java/io/openaev/database/model/Scenario.java b/openaev-model/src/main/java/io/openaev/database/model/Scenario.java index eff4f18b0ab..f727c0305fd 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Scenario.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Scenario.java @@ -2,6 +2,7 @@ import static io.openaev.database.model.Grant.GRANT_TYPE.OBSERVER; import static io.openaev.database.model.Grant.GRANT_TYPE.PLANNER; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static io.openaev.helper.UserHelper.getUsersByType; import static java.time.Instant.now; import static lombok.AccessLevel.NONE; @@ -368,6 +369,12 @@ public void setExercises(List exercises) { @JsonProperty("scenario_lessons_anonymized") private boolean lessonsAnonymized = false; + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Getter(onMethod_ = @JsonIgnore) @Transient private final ResourceType resourceType = ResourceType.SCENARIO; diff --git a/openaev-model/src/main/java/io/openaev/database/model/Tag.java b/openaev-model/src/main/java/io/openaev/database/model/Tag.java index 9d792f01789..a4827dba2bb 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Tag.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Tag.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -100,6 +101,12 @@ public class Tag implements Base { @UpdateTimestamp private Instant updatedAt = now(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Getter(onMethod_ = @JsonIgnore) @Transient private final ResourceType resourceType = ResourceType.TAG; diff --git a/openaev-model/src/main/java/io/openaev/database/model/TagRule.java b/openaev-model/src/main/java/io/openaev/database/model/TagRule.java index 5ab37d26834..3c08f370327 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/TagRule.java +++ b/openaev-model/src/main/java/io/openaev/database/model/TagRule.java @@ -1,6 +1,7 @@ package io.openaev.database.model; import static io.openaev.database.model.Tag.*; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -8,6 +9,7 @@ import io.openaev.database.audit.ModelBaseListener; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -57,6 +59,12 @@ public class TagRule implements Base { @JsonProperty("tag_rule_asset_groups") private List assetGroups = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @Getter(onMethod_ = @JsonIgnore) @Transient private final ResourceType resourceType = ResourceType.TAG_RULE; diff --git a/openaev-model/src/main/java/io/openaev/database/model/Team.java b/openaev-model/src/main/java/io/openaev/database/model/Team.java index a3b16683bce..bf7159ea8a7 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Team.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Team.java @@ -1,5 +1,6 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; import static java.time.Instant.now; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -73,6 +74,12 @@ public class Team implements Base { @UpdateTimestamp private Instant updatedAt = now(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + @ArraySchema( schema = @Schema(description = "IDs of the tags of the team", implementation = String.class)) @Queryable(filterable = true, dynamicValues = true, path = "tags.id") diff --git a/openaev-model/src/main/java/io/openaev/database/model/Tenant.java b/openaev-model/src/main/java/io/openaev/database/model/Tenant.java index e87c67e17fc..b92ddbb0982 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Tenant.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Tenant.java @@ -21,6 +21,9 @@ @EntityListeners(ModelBaseListener.class) public class Tenant implements Base { + // Same default ID for XTM HUB and OpenAEV instances + public static String DEFAULT_TENANT_UUID = "2cffad3a-0001-4078-b0e2-ef74274022c3"; + @Id @GeneratedValue(generator = "UUID") @UuidGenerator @@ -55,4 +58,14 @@ public class Tenant implements Base { @NotNull @JsonProperty("tenant_updated_at") private Instant updatedAt = now(); + + @Column(name = "tenant_deleted_at") + @JsonProperty("tenant_deleted_at") + private Instant deletedAt; + + public Tenant() {} + + public Tenant(String id) { + this.id = id; + } } diff --git a/openaev-model/src/main/java/io/openaev/database/model/Vulnerability.java b/openaev-model/src/main/java/io/openaev/database/model/Vulnerability.java index 6f4a56374b2..36963721f2c 100644 --- a/openaev-model/src/main/java/io/openaev/database/model/Vulnerability.java +++ b/openaev-model/src/main/java/io/openaev/database/model/Vulnerability.java @@ -1,5 +1,7 @@ package io.openaev.database.model; +import static io.openaev.database.model.Tenant.DEFAULT_TENANT_UUID; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -112,6 +114,12 @@ public enum VulnerabilityStatus { @JsonProperty("vulnerabilities_cwes") private List cwes = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "tenant_id") + @JsonIgnore + @NotNull + private Tenant tenant = new Tenant(DEFAULT_TENANT_UUID); + // -- AUDIT -- @CreationTimestamp