From 34f025c94c693a7362c420197c68775ebaa9179c Mon Sep 17 00:00:00 2001 From: Romuald Lemesle Date: Thu, 28 Dec 2023 11:44:18 +0100 Subject: [PATCH] [backend] Asset, Endpoint & AssetGroup (#268) --- .../migration/V2_64__Assets_Asset_Groups.java | 60 +++++++++++ .../rest/asset/endpoint/EndpointApi.java | 33 +++--- .../asset/endpoint/form/EndpointInput.java | 23 ++-- .../io/openex/rest/asset/form/AssetInput.java | 15 +-- .../rest/asset_group/AssetGroupApi.java | 33 ++---- .../asset_group/form/AssetGroupInput.java | 8 +- .../io/openex/service/AssetGroupService.java | 42 ++++++++ .../openex/service/asset/EndpointService.java | 42 ++++++++ .../openex/service/AssetGroupServiceTest.java | 42 ++------ .../openex/service/EndpointServiceTest.java | 102 ++++++++++++++++++ .../annotation/Ipv4OrIpv6Constraint.java | 6 +- .../java/io/openex/database/model/Asset.java | 57 ++-------- .../io/openex/database/model/AssetGroup.java | 22 +--- .../io/openex/database/model/Endpoint.java | 40 +++---- .../repository/AssetGroupRepository.java | 16 +-- .../database/repository/AssetRepository.java | 11 +- .../repository/EndpointRepository.java | 15 +-- .../openex/validator/Ipv4OrIpv6Validator.java | 11 +- pom.xml | 3 +- 19 files changed, 328 insertions(+), 253 deletions(-) create mode 100644 openex-api/src/main/java/io/openex/migration/V2_64__Assets_Asset_Groups.java create mode 100644 openex-api/src/main/java/io/openex/service/AssetGroupService.java create mode 100644 openex-api/src/main/java/io/openex/service/asset/EndpointService.java create mode 100644 openex-api/src/test/java/io/openex/service/EndpointServiceTest.java diff --git a/openex-api/src/main/java/io/openex/migration/V2_64__Assets_Asset_Groups.java b/openex-api/src/main/java/io/openex/migration/V2_64__Assets_Asset_Groups.java new file mode 100644 index 0000000000..4c1e694254 --- /dev/null +++ b/openex-api/src/main/java/io/openex/migration/V2_64__Assets_Asset_Groups.java @@ -0,0 +1,60 @@ +package io.openex.migration; + +import org.flywaydb.core.api.migration.BaseJavaMigration; +import org.flywaydb.core.api.migration.Context; +import org.springframework.stereotype.Component; + +import java.sql.Connection; +import java.sql.Statement; + +@Component +public class V2_64__Assets_Asset_Groups extends BaseJavaMigration { + + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + // Create table asset + select.execute(""" + CREATE TABLE IF NOT EXISTS assets ( + asset_id varchar(255) not null constraint assets_pkey primary key, + asset_external_id varchar(255), + asset_name varchar(255) not null, + asset_description text, + asset_created_at timestamp not null default now(), + asset_updated_at timestamp not null default now() + ); + CREATE INDEX IF NOT EXISTS idx_assets on assets (asset_id); + """); + // Create table endpoint + select.execute(""" + CREATE TABLE IF NOT EXISTS endpoints ( + endpoint_id varchar(255) not null constraint endpoints_pkey primary key, + endpoint_ip varchar(255) not null, + endpoint_hostname varchar(255), + endpoint_os varchar(255) + ) INHERITS (assets); + """); + // Create table asset groups + select.execute(""" + CREATE TABLE IF NOT EXISTS asset_groups ( + asset_group_id varchar(255) not null constraint asset_groups_pkey primary key, + asset_group_name varchar(255) not null, + asset_group_description text, + asset_group_created_at timestamp not null default now(), + asset_group_updated_at timestamp not null default now() + ); + CREATE INDEX IF NOT EXISTS idx_asset_groups on asset_groups (asset_group_id); + """); + // Add association table between asset and asset groups + select.execute(""" + CREATE TABLE IF NOT EXISTS asset_groups_assets ( + asset_group_id varchar(255) not null constraint asset_group_id_fk references asset_groups on delete cascade, + asset_id varchar(255) not null constraint asset_id_fk references endpoints on delete cascade, + constraint asset_groups_assets_pkey primary key (asset_group_id, asset_id) + ); + CREATE INDEX IF NOT EXISTS idx_asset_groups_assets_asset on asset_groups_assets (asset_group_id); + CREATE INDEX IF NOT EXISTS idx_asset_groups_assets_asset on asset_groups_assets (asset_id); + """); + } +} diff --git a/openex-api/src/main/java/io/openex/rest/asset/endpoint/EndpointApi.java b/openex-api/src/main/java/io/openex/rest/asset/endpoint/EndpointApi.java index 841262a0f7..bfc4312182 100644 --- a/openex-api/src/main/java/io/openex/rest/asset/endpoint/EndpointApi.java +++ b/openex-api/src/main/java/io/openex/rest/asset/endpoint/EndpointApi.java @@ -1,20 +1,18 @@ package io.openex.rest.asset.endpoint; import io.openex.database.model.Endpoint; -import io.openex.database.repository.TagRepository; import io.openex.rest.asset.endpoint.form.EndpointInput; -import io.openex.service.AssetEndpointService; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotBlank; +import io.openex.service.asset.EndpointService; import lombok.RequiredArgsConstructor; -import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +import javax.annotation.security.RolesAllowed; +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; import java.util.List; import static io.openex.database.model.User.ROLE_ADMIN; -import static io.openex.helper.StreamHelper.fromIterable; @RequiredArgsConstructor @RestController @@ -22,40 +20,35 @@ public class EndpointApi { public static final String ENDPOINT_URI = "/api/endpoints"; - private final AssetEndpointService assetEndpointService; - private final TagRepository tagRepository; + private final EndpointService endpointService; @PostMapping(ENDPOINT_URI) - @Secured(ROLE_ADMIN) + @RolesAllowed(ROLE_ADMIN) public Endpoint createEndpoint(@Valid @RequestBody final EndpointInput input) { Endpoint endpoint = new Endpoint(); endpoint.setUpdateAttributes(input); - endpoint.setPlatform(input.getPlatform()); - endpoint.setTags(fromIterable(this.tagRepository.findAllById(input.getTagIds()))); - return this.assetEndpointService.createEndpoint(endpoint); + return this.endpointService.createEndpoint(endpoint); } @GetMapping(ENDPOINT_URI) @PreAuthorize("isObserver()") public List endpoints() { - return this.assetEndpointService.endpoints(); + return this.endpointService.endpoints(); } @PutMapping(ENDPOINT_URI + "/{endpointId}") - @Secured(ROLE_ADMIN) + @RolesAllowed(ROLE_ADMIN) public Endpoint updateEndpoint( @PathVariable @NotBlank final String endpointId, @Valid @RequestBody final EndpointInput input) { - Endpoint endpoint = this.assetEndpointService.endpoint(endpointId); + Endpoint endpoint = this.endpointService.endpoint(endpointId); endpoint.setUpdateAttributes(input); - endpoint.setPlatform(input.getPlatform()); - endpoint.setTags(fromIterable(this.tagRepository.findAllById(input.getTagIds()))); - return this.assetEndpointService.updateEndpoint(endpoint); + return this.endpointService.updateEndpoint(endpoint); } @DeleteMapping(ENDPOINT_URI + "/{endpointId}") - @Secured(ROLE_ADMIN) + @RolesAllowed(ROLE_ADMIN) public void deleteEndpoint(@PathVariable @NotBlank final String endpointId) { - this.assetEndpointService.deleteEndpoint(endpointId); + this.endpointService.deleteEndpoint(endpointId); } } diff --git a/openex-api/src/main/java/io/openex/rest/asset/endpoint/form/EndpointInput.java b/openex-api/src/main/java/io/openex/rest/asset/endpoint/form/EndpointInput.java index 424c1f46a1..287ff26629 100644 --- a/openex-api/src/main/java/io/openex/rest/asset/endpoint/form/EndpointInput.java +++ b/openex-api/src/main/java/io/openex/rest/asset/endpoint/form/EndpointInput.java @@ -1,33 +1,28 @@ package io.openex.rest.asset.endpoint.form; import com.fasterxml.jackson.annotation.JsonProperty; -import io.openex.database.model.Endpoint; import io.openex.rest.asset.form.AssetInput; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; import lombok.Data; import lombok.EqualsAndHashCode; +import javax.validation.constraints.NotBlank; + import static io.openex.config.AppConfig.MANDATORY_MESSAGE; @EqualsAndHashCode(callSuper = true) @Data public class EndpointInput extends AssetInput { - @NotEmpty(message = MANDATORY_MESSAGE) - @Size(min = 1, message = MANDATORY_MESSAGE) - @JsonProperty("endpoint_ips") - private String[] ips; + + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("endpoint_ip") + private String ip; @JsonProperty("endpoint_hostname") private String hostname; - @NotNull(message = MANDATORY_MESSAGE) - @JsonProperty("endpoint_platform") - private Endpoint.PLATFORM_TYPE platform; - - @JsonProperty("endpoint_mac_adresses") - private String[] macAdresses; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("endpoint_os") + private String os; } diff --git a/openex-api/src/main/java/io/openex/rest/asset/form/AssetInput.java b/openex-api/src/main/java/io/openex/rest/asset/form/AssetInput.java index 9ecab94ea0..09aa5d42be 100644 --- a/openex-api/src/main/java/io/openex/rest/asset/form/AssetInput.java +++ b/openex-api/src/main/java/io/openex/rest/asset/form/AssetInput.java @@ -3,17 +3,16 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; -import jakarta.validation.constraints.NotBlank; - -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; +import javax.validation.constraints.NotBlank; import static io.openex.config.AppConfig.MANDATORY_MESSAGE; @Data public abstract class AssetInput { + @JsonProperty("asset_external_id") + private String externalId; + @NotBlank(message = MANDATORY_MESSAGE) @JsonProperty("asset_name") private String name; @@ -21,10 +20,4 @@ public abstract class AssetInput { @JsonProperty("asset_description") private String description; - @JsonProperty("asset_last_seen") - private Instant lastSeen; - - @JsonProperty("asset_tags") - private List tagIds = new ArrayList<>(); - } diff --git a/openex-api/src/main/java/io/openex/rest/asset_group/AssetGroupApi.java b/openex-api/src/main/java/io/openex/rest/asset_group/AssetGroupApi.java index 1930881327..3dead6bba5 100644 --- a/openex-api/src/main/java/io/openex/rest/asset_group/AssetGroupApi.java +++ b/openex-api/src/main/java/io/openex/rest/asset_group/AssetGroupApi.java @@ -1,21 +1,18 @@ package io.openex.rest.asset_group; import io.openex.database.model.AssetGroup; -import io.openex.database.repository.TagRepository; import io.openex.rest.asset_group.form.AssetGroupInput; -import io.openex.rest.asset_group.form.UpdateAssetsOnAssetGroupInput; import io.openex.service.AssetGroupService; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotBlank; import lombok.RequiredArgsConstructor; -import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +import javax.annotation.security.RolesAllowed; +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; import java.util.List; import static io.openex.database.model.User.ROLE_ADMIN; -import static io.openex.helper.StreamHelper.fromIterable; @RestController @RequiredArgsConstructor @@ -24,14 +21,12 @@ public class AssetGroupApi { public static final String ASSET_GROUP_URI = "/api/asset_groups"; private final AssetGroupService assetGroupService; - private final TagRepository tagRepository; @PostMapping(ASSET_GROUP_URI) - @Secured(ROLE_ADMIN) + @RolesAllowed(ROLE_ADMIN) public AssetGroup createAssetGroup(@Valid @RequestBody final AssetGroupInput input) { AssetGroup assetGroup = new AssetGroup(); assetGroup.setUpdateAttributes(input); - assetGroup.setTags(fromIterable(this.tagRepository.findAllById(input.getTagIds()))); return this.assetGroupService.createAssetGroup(assetGroup); } @@ -41,34 +36,18 @@ public List assetGroups() { return this.assetGroupService.assetGroups(); } - @GetMapping(ASSET_GROUP_URI + "/{assetGroupId}") - @PreAuthorize("isObserver()") - public AssetGroup assetGroup(@PathVariable @NotBlank final String assetGroupId) { - return this.assetGroupService.assetGroup(assetGroupId); - } - @PutMapping(ASSET_GROUP_URI + "/{assetGroupId}") - @Secured(ROLE_ADMIN) + @RolesAllowed(ROLE_ADMIN) public AssetGroup updateAssetGroup( @PathVariable @NotBlank final String assetGroupId, @Valid @RequestBody final AssetGroupInput input) { AssetGroup assetGroup = this.assetGroupService.assetGroup(assetGroupId); assetGroup.setUpdateAttributes(input); - assetGroup.setTags(fromIterable(this.tagRepository.findAllById(input.getTagIds()))); return this.assetGroupService.updateAssetGroup(assetGroup); } - @PutMapping(ASSET_GROUP_URI + "/{assetGroupId}/assets") - @Secured(ROLE_ADMIN) - public AssetGroup updateAssetsOnAssetGroup( - @PathVariable @NotBlank final String assetGroupId, - @Valid @RequestBody final UpdateAssetsOnAssetGroupInput input) { - AssetGroup assetGroup = this.assetGroupService.assetGroup(assetGroupId); - return this.assetGroupService.updateAssetsOnAssetGroup(assetGroup, input.getAssetIds()); - } - @DeleteMapping(ASSET_GROUP_URI + "/{assetGroupId}") - @Secured(ROLE_ADMIN) + @RolesAllowed(ROLE_ADMIN) public void deleteAssetGroup(@PathVariable @NotBlank final String assetGroupId) { this.assetGroupService.deleteAssetGroup(assetGroupId); } diff --git a/openex-api/src/main/java/io/openex/rest/asset_group/form/AssetGroupInput.java b/openex-api/src/main/java/io/openex/rest/asset_group/form/AssetGroupInput.java index 0d76fc0bf0..fee57f4065 100644 --- a/openex-api/src/main/java/io/openex/rest/asset_group/form/AssetGroupInput.java +++ b/openex-api/src/main/java/io/openex/rest/asset_group/form/AssetGroupInput.java @@ -4,10 +4,7 @@ import lombok.Getter; import lombok.Setter; -import jakarta.validation.constraints.NotBlank; - -import java.util.ArrayList; -import java.util.List; +import javax.validation.constraints.NotBlank; import static io.openex.config.AppConfig.MANDATORY_MESSAGE; @@ -21,7 +18,4 @@ public class AssetGroupInput { @JsonProperty("asset_group_description") private String description; - - @JsonProperty("asset_group_tags") - private List tagIds = new ArrayList<>(); } diff --git a/openex-api/src/main/java/io/openex/service/AssetGroupService.java b/openex-api/src/main/java/io/openex/service/AssetGroupService.java new file mode 100644 index 0000000000..1039678c14 --- /dev/null +++ b/openex-api/src/main/java/io/openex/service/AssetGroupService.java @@ -0,0 +1,42 @@ +package io.openex.service; + +import io.openex.database.model.AssetGroup; +import io.openex.database.repository.AssetGroupRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +import static io.openex.helper.StreamHelper.fromIterable; +import static java.time.Instant.now; + +@RequiredArgsConstructor +@Service +public class AssetGroupService { + + private final AssetGroupRepository assetGroupRepository; + + public AssetGroup createAssetGroup(@NotNull final AssetGroup assetGroup) { + return this.assetGroupRepository.save(assetGroup); + } + + public AssetGroup assetGroup(@NotBlank final String assetGroupId) { + return this.assetGroupRepository.findById(assetGroupId).orElseThrow(); + } + + public List assetGroups() { + return fromIterable(this.assetGroupRepository.findAll()); + } + + public AssetGroup updateAssetGroup(@NotNull final AssetGroup assetGroup) { + assetGroup.setUpdatedAt(now()); + return this.assetGroupRepository.save(assetGroup); + } + + public void deleteAssetGroup(@NotBlank final String assetGroupId) { + this.assetGroupRepository.deleteById(assetGroupId); + } + +} diff --git a/openex-api/src/main/java/io/openex/service/asset/EndpointService.java b/openex-api/src/main/java/io/openex/service/asset/EndpointService.java new file mode 100644 index 0000000000..f17016cd1e --- /dev/null +++ b/openex-api/src/main/java/io/openex/service/asset/EndpointService.java @@ -0,0 +1,42 @@ +package io.openex.service.asset; + +import io.openex.database.model.Endpoint; +import io.openex.database.repository.EndpointRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +import static io.openex.helper.StreamHelper.fromIterable; +import static java.time.Instant.now; + +@RequiredArgsConstructor +@Service +public class EndpointService { + + private final EndpointRepository endpointRepository; + + public Endpoint createEndpoint(@NotNull final Endpoint endpoint) { + return this.endpointRepository.save(endpoint); + } + + public Endpoint endpoint(@NotBlank final String endpointId) { + return this.endpointRepository.findById(endpointId).orElseThrow(); + } + + public List endpoints() { + return fromIterable(this.endpointRepository.findAll()); + } + + public Endpoint updateEndpoint(@NotNull final Endpoint endpoint) { + endpoint.setUpdatedAt(now()); + return this.endpointRepository.save(endpoint); + } + + public void deleteEndpoint(@NotBlank final String endpointId) { + this.endpointRepository.deleteById(endpointId); + } + +} diff --git a/openex-api/src/test/java/io/openex/service/AssetGroupServiceTest.java b/openex-api/src/test/java/io/openex/service/AssetGroupServiceTest.java index db487de814..faf47cef6b 100644 --- a/openex-api/src/test/java/io/openex/service/AssetGroupServiceTest.java +++ b/openex-api/src/test/java/io/openex/service/AssetGroupServiceTest.java @@ -1,9 +1,8 @@ package io.openex.service; -import io.openex.database.model.AssetGroup; import io.openex.database.model.Endpoint; -import io.openex.database.model.Tag; -import io.openex.database.repository.TagRepository; +import io.openex.database.model.AssetGroup; +import io.openex.service.asset.EndpointService; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -11,7 +10,7 @@ import java.util.List; import java.util.NoSuchElementException; -import static io.openex.database.model.Endpoint.PLATFORM_TYPE.Linux; +import static io.openex.database.model.Endpoint.OS_TYPE.LINUX; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest @@ -21,9 +20,7 @@ public class AssetGroupServiceTest { @Autowired private AssetGroupService assetGroupService; @Autowired - private AssetEndpointService assetEndpointService; - @Autowired - private TagRepository tagRepository; + private EndpointService endpointService; static String ASSET_GROUP_ID; @@ -66,10 +63,12 @@ void updateAssetGroupTest() { Endpoint endpoint = new Endpoint(); String name = "Personal PC"; endpoint.setName(name); - endpoint.setIps(new String[]{"127.0.0.1"}); + endpoint.setIp("127.0.0.1"); + endpoint.setHostname("hostname"); + endpoint.setOs(LINUX); endpoint.setHostname("hostname"); - endpoint.setPlatform(Linux); - Endpoint endpointCreated = this.assetEndpointService.createEndpoint(endpoint); + endpoint.setOs(LINUX); + Endpoint endpointCreated = this.endpointService.createEndpoint(endpoint); AssetGroup assetGroup = this.assetGroupService.assetGroup(ASSET_GROUP_ID); String value = "Professional network"; @@ -78,32 +77,13 @@ void updateAssetGroupTest() { // -- EXECUTE -- AssetGroup assetGroupUpdated = this.assetGroupService.updateAssetGroup(assetGroup); - assertNotNull(assetGroupUpdated); + assertNotNull(assetGroup); assertEquals(value, assetGroupUpdated.getName()); } - @DisplayName("Update asset group with tag") - @Test - @Order(4) - void updateAssetGroupWithTagTest() { - // -- PREPARE -- - Tag tag = new Tag(); - String tagName = "endpoint"; - tag.setName(tagName); - tag.setColor("blue"); - Tag tagCreated = this.tagRepository.save(tag); - AssetGroup assetGroup = this.assetGroupService.assetGroup(ASSET_GROUP_ID); - assetGroup.setTags(List.of(tagCreated)); - - // -- EXECUTE -- - AssetGroup assetGroupUpdated = this.assetGroupService.updateAssetGroup(assetGroup); - assertNotNull(assetGroupUpdated); - assertEquals(tagName, assetGroupUpdated.getTags().get(0).getName()); - } - @DisplayName("Delete asset group") @Test - @Order(5) + @Order(4) void deleteAssetGroupTest() { this.assetGroupService.deleteAssetGroup(ASSET_GROUP_ID); assertThrows(NoSuchElementException.class, () -> this.assetGroupService.assetGroup(ASSET_GROUP_ID)); diff --git a/openex-api/src/test/java/io/openex/service/EndpointServiceTest.java b/openex-api/src/test/java/io/openex/service/EndpointServiceTest.java new file mode 100644 index 0000000000..c4b338b576 --- /dev/null +++ b/openex-api/src/test/java/io/openex/service/EndpointServiceTest.java @@ -0,0 +1,102 @@ +package io.openex.service; + +import io.openex.database.model.Endpoint; +import io.openex.service.asset.EndpointService; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.TransactionSystemException; + +import java.util.List; +import java.util.NoSuchElementException; + +import static io.openex.database.model.Endpoint.OS_TYPE.LINUX; +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class EndpointServiceTest { + + @Autowired + private EndpointService endpointService; + + static String ENDPOINT_ID; + + @DisplayName("Create endpoint failed") + @Test + @Order(1) + void createEndpointFailedTest() { + // -- PREPARE -- + Endpoint endpoint = new Endpoint(); + String name = "Personal PC"; + endpoint.setName(name); + endpoint.setIp("wrong ip"); + endpoint.setHostname("hostname"); + endpoint.setOs(LINUX); + endpoint.setHostname("hostname"); + endpoint.setOs(LINUX); + + // -- EXECUTE -- + assertThrows(TransactionSystemException.class, () -> this.endpointService.createEndpoint(endpoint)); + } + + @DisplayName("Create endpoint succeed") + @Test + @Order(2) + void createEndpointSucceedTest() { + // -- PREPARE -- + Endpoint endpoint = new Endpoint(); + String name = "Personal PC"; + endpoint.setName(name); + endpoint.setIp("127.0.0.1"); + endpoint.setHostname("hostname"); + endpoint.setOs(LINUX); + endpoint.setHostname("hostname"); + endpoint.setOs(LINUX); + + // -- EXECUTE -- + Endpoint endpointCreated = this.endpointService.createEndpoint(endpoint); + ENDPOINT_ID = endpointCreated.getId(); + assertNotNull(endpointCreated); + assertNotNull(endpointCreated.getId()); + assertNotNull(endpointCreated.getCreatedAt()); + assertNotNull(endpointCreated.getUpdatedAt()); + assertEquals(name, endpointCreated.getName()); + } + + @DisplayName("Retrieve endpoint") + @Test + @Order(3) + void retrieveEndpointTest() { + Endpoint endpoint = this.endpointService.endpoint(ENDPOINT_ID); + assertNotNull(endpoint); + + List endpoints = this.endpointService.endpoints(); + assertNotNull(endpoints); + assertEquals(ENDPOINT_ID, endpoints.get(0).getId()); + } + + @DisplayName("Update endpoint") + @Test + @Order(4) + void updateEndpointTest() { + // -- PREPARE -- + Endpoint endpoint = this.endpointService.endpoint(ENDPOINT_ID); + String value = "Professional PC"; + endpoint.setName(value); + + // -- EXECUTE -- + Endpoint endpointUpdated = this.endpointService.updateEndpoint(endpoint); + assertNotNull(endpoint); + assertEquals(value, endpointUpdated.getName()); + } + + @DisplayName("Delete endpoint") + @Test + @Order(5) + void deleteEndpointTest() { + this.endpointService.deleteEndpoint(ENDPOINT_ID); + assertThrows(NoSuchElementException.class, () -> this.endpointService.endpoint(ENDPOINT_ID)); + } + +} diff --git a/openex-model/src/main/java/io/openex/annotation/Ipv4OrIpv6Constraint.java b/openex-model/src/main/java/io/openex/annotation/Ipv4OrIpv6Constraint.java index 657a7bf710..dc4507f1c5 100644 --- a/openex-model/src/main/java/io/openex/annotation/Ipv4OrIpv6Constraint.java +++ b/openex-model/src/main/java/io/openex/annotation/Ipv4OrIpv6Constraint.java @@ -2,9 +2,9 @@ import io.openex.validator.Ipv4OrIpv6Validator; -import jakarta.validation.Constraint; -import jakarta.validation.Payload; -import jakarta.validation.ReportAsSingleViolation; +import javax.validation.Constraint; +import javax.validation.Payload; +import javax.validation.ReportAsSingleViolation; import java.lang.annotation.Retention; import java.lang.annotation.Target; diff --git a/openex-model/src/main/java/io/openex/database/model/Asset.java b/openex-model/src/main/java/io/openex/database/model/Asset.java index f18caae895..7e77085326 100644 --- a/openex-model/src/main/java/io/openex/database/model/Asset.java +++ b/openex-model/src/main/java/io/openex/database/model/Asset.java @@ -1,58 +1,33 @@ package io.openex.database.model; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.hypersistence.utils.hibernate.type.basic.PostgreSQLHStoreType; import io.openex.database.audit.ModelBaseListener; -import io.openex.helper.MultiIdDeserializer; import lombok.Data; -import lombok.Setter; - -import jakarta.persistence.*; -import jakarta.validation.constraints.NotBlank; -import org.hibernate.annotations.Type; -import org.hibernate.annotations.UuidGenerator; +import org.hibernate.annotations.GenericGenerator; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; import java.time.Instant; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import static java.time.Instant.now; -import static jakarta.persistence.DiscriminatorType.STRING; -import static lombok.AccessLevel.NONE; @Data @Entity @Table(name = "assets") -@Inheritance(strategy = InheritanceType.SINGLE_TABLE) -@DiscriminatorColumn(name="asset_type", discriminatorType = STRING) +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @EntityListeners(ModelBaseListener.class) public class Asset implements Base { @Id @Column(name = "asset_id") @GeneratedValue(generator = "UUID") - @UuidGenerator + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") @JsonProperty("asset_id") - @NotBlank private String id; - @Column(name = "asset_type", insertable = false, updatable = false) - @JsonProperty("asset_type") - @Setter(NONE) - private String type; - - @Column(name = "asset_sources") - @JsonProperty("asset_sources") - @Type(PostgreSQLHStoreType.class) - private Map sources = new HashMap<>(); - - @Column(name = "asset_blobs") - @JsonProperty("asset_blobs") - @Type(PostgreSQLHStoreType.class) - private Map blobs = new HashMap<>(); + @Column(name = "asset_external_id") + @JsonProperty("asset_external_id") + private String externalId; @NotBlank @Column(name = "asset_name") @@ -63,22 +38,6 @@ public class Asset implements Base { @JsonProperty("asset_description") private String description; - @Column(name = "asset_last_seen") - @JsonProperty("asset_last_seen") - private Instant lastSeen; - - // -- TAG -- - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "assets_tags", - joinColumns = @JoinColumn(name = "asset_id"), - inverseJoinColumns = @JoinColumn(name = "tag_id")) - @JsonSerialize(using = MultiIdDeserializer.class) - @JsonProperty("asset_tags") - private List tags = new ArrayList<>(); - - // -- AUDIT -- - @Column(name = "asset_created_at") @JsonProperty("asset_created_at") private Instant createdAt = now(); diff --git a/openex-model/src/main/java/io/openex/database/model/AssetGroup.java b/openex-model/src/main/java/io/openex/database/model/AssetGroup.java index d0fc6b1f8e..5537239ae3 100644 --- a/openex-model/src/main/java/io/openex/database/model/AssetGroup.java +++ b/openex-model/src/main/java/io/openex/database/model/AssetGroup.java @@ -5,11 +5,10 @@ import io.openex.database.audit.ModelBaseListener; import io.openex.helper.MultiIdDeserializer; import lombok.Data; +import org.hibernate.annotations.GenericGenerator; -import jakarta.persistence.*; -import jakarta.validation.constraints.NotBlank; -import org.hibernate.annotations.UuidGenerator; - +import javax.persistence.*; +import javax.validation.constraints.NotBlank; import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -25,9 +24,8 @@ public class AssetGroup implements Base { @Id @Column(name = "asset_group_id") @GeneratedValue(generator = "UUID") - @UuidGenerator + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") @JsonProperty("asset_group_id") - @NotBlank private String id; @NotBlank @@ -47,18 +45,6 @@ public class AssetGroup implements Base { @JsonProperty("asset_group_assets") private List assets = new ArrayList<>(); - // -- TAG -- - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "asset_groups_tags", - joinColumns = @JoinColumn(name = "asset_group_id"), - inverseJoinColumns = @JoinColumn(name = "tag_id")) - @JsonSerialize(using = MultiIdDeserializer.class) - @JsonProperty("asset_group_tags") - private List tags = new ArrayList<>(); - - // -- AUDIT -- - @Column(name = "asset_group_created_at") @JsonProperty("asset_group_created_at") private Instant createdAt = now(); diff --git a/openex-model/src/main/java/io/openex/database/model/Endpoint.java b/openex-model/src/main/java/io/openex/database/model/Endpoint.java index e68681ba7a..59658d6b09 100644 --- a/openex-model/src/main/java/io/openex/database/model/Endpoint.java +++ b/openex-model/src/main/java/io/openex/database/model/Endpoint.java @@ -3,49 +3,37 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openex.annotation.Ipv4OrIpv6Constraint; import io.openex.database.audit.ModelBaseListener; -import jakarta.persistence.*; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; import lombok.Data; import lombok.EqualsAndHashCode; -import org.hibernate.annotations.Type; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; @EqualsAndHashCode(callSuper = true) @Data @Entity -@DiscriminatorValue("Endpoint") +@Table(name = "endpoints") @EntityListeners(ModelBaseListener.class) public class Endpoint extends Asset { - public enum PLATFORM_TYPE { - @JsonProperty("Linux") - Linux, - @JsonProperty("Windows") - Windows, - @JsonProperty("Darwin") - Darwin, + public enum OS_TYPE { + LINUX, + WINDOWS, } - @NotEmpty + @NotBlank @Ipv4OrIpv6Constraint - @Type(value = io.openex.database.converter.PostgreSqlStringArrayType.class) - @Column(name = "endpoint_ips") - @JsonProperty("endpoint_ips") - private String[] ips; + @Column(name = "endpoint_ip") + @JsonProperty("endpoint_ip") + private String ip; @Column(name = "endpoint_hostname") @JsonProperty("endpoint_hostname") private String hostname; - @Column(name = "endpoint_platform") - @JsonProperty("endpoint_platform") + @Column(name = "endpoint_os") + @JsonProperty("endpoint_os") @Enumerated(EnumType.STRING) - @NotNull - private PLATFORM_TYPE platform; - - @Type(value = io.openex.database.converter.PostgreSqlStringArrayType.class) - @Column(name = "endpoint_mac_addresses") - @JsonProperty("endpoint_mac_addresses") - private String[] macAddresses; + private OS_TYPE os; } diff --git a/openex-model/src/main/java/io/openex/database/repository/AssetGroupRepository.java b/openex-model/src/main/java/io/openex/database/repository/AssetGroupRepository.java index 85e6a481c4..2ae18a26da 100644 --- a/openex-model/src/main/java/io/openex/database/repository/AssetGroupRepository.java +++ b/openex-model/src/main/java/io/openex/database/repository/AssetGroupRepository.java @@ -1,22 +1,8 @@ package io.openex.database.repository; -import io.openex.database.model.Asset; import io.openex.database.model.AssetGroup; -import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; -import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import jakarta.validation.constraints.NotBlank; -import java.util.List; - @Repository -public interface AssetGroupRepository extends CrudRepository { - - @Query("select asset from Asset asset " - + "inner join AssetGroupAsset aga on aga.assetId = asset.id " - + "inner join AssetGroup assetGroup on aga.assetGroupId = assetGroup.id " - + "where assetGroup.id = :assetGroupId") - List assetsFromAssetGroup(@NotBlank @Param("assetGroupId") final String assetGroupId); - -} +public interface AssetGroupRepository extends CrudRepository { } diff --git a/openex-model/src/main/java/io/openex/database/repository/AssetRepository.java b/openex-model/src/main/java/io/openex/database/repository/AssetRepository.java index e6b9908c25..3d06196b95 100644 --- a/openex-model/src/main/java/io/openex/database/repository/AssetRepository.java +++ b/openex-model/src/main/java/io/openex/database/repository/AssetRepository.java @@ -1,17 +1,8 @@ package io.openex.database.repository; import io.openex.database.model.Asset; -import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; -import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; - @Repository -public interface AssetRepository extends CrudRepository { - - @Query("select a from Asset a where a.type IN :types") - List findByType(@Param("types") final List types); - -} +public interface AssetRepository extends CrudRepository { } diff --git a/openex-model/src/main/java/io/openex/database/repository/EndpointRepository.java b/openex-model/src/main/java/io/openex/database/repository/EndpointRepository.java index 345a97c37e..1b046b9dd7 100644 --- a/openex-model/src/main/java/io/openex/database/repository/EndpointRepository.java +++ b/openex-model/src/main/java/io/openex/database/repository/EndpointRepository.java @@ -1,21 +1,8 @@ package io.openex.database.repository; import io.openex.database.model.Endpoint; -import jakarta.validation.constraints.NotBlank; -import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; -import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository -public interface EndpointRepository extends CrudRepository { - - @Query(value = "select e.* from assets e where e.asset_sources[:sourceKey] = :sourceValue", nativeQuery = true) - Optional findBySource( - @NotBlank final @Param("sourceKey") String sourceKey, - @NotBlank final @Param("sourceValue") String sourceValue - ); - -} +public interface EndpointRepository extends CrudRepository { } diff --git a/openex-model/src/main/java/io/openex/validator/Ipv4OrIpv6Validator.java b/openex-model/src/main/java/io/openex/validator/Ipv4OrIpv6Validator.java index 4f434f7a08..ce83d864f7 100644 --- a/openex-model/src/main/java/io/openex/validator/Ipv4OrIpv6Validator.java +++ b/openex-model/src/main/java/io/openex/validator/Ipv4OrIpv6Validator.java @@ -1,18 +1,17 @@ package io.openex.validator; import io.openex.annotation.Ipv4OrIpv6Constraint; -import jakarta.validation.ConstraintValidator; -import jakarta.validation.ConstraintValidatorContext; import org.apache.commons.validator.routines.InetAddressValidator; -import java.util.Arrays; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; -public class Ipv4OrIpv6Validator implements ConstraintValidator { +public class Ipv4OrIpv6Validator implements ConstraintValidator { @Override - public boolean isValid(final String[] ips, final ConstraintValidatorContext cxt) { + public boolean isValid(final String ip, final ConstraintValidatorContext cxt) { InetAddressValidator validator = InetAddressValidator.getInstance(); - return Arrays.stream(ips).allMatch(validator::isValid); + return validator.isValid(ip); } } diff --git a/pom.xml b/pom.xml index d015d5ef9b..97a9313e4f 100644 --- a/pom.xml +++ b/pom.xml @@ -22,8 +22,7 @@ 2.0.1.Final 2.15.0 1.8.0 - 3.12.1 - 0.8.11 + 3.11.0