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 index 4c1e694254..d801e8cbc4 100644 --- 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 @@ -29,11 +29,30 @@ asset_updated_at timestamp not null default now() // 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) + endpoint_os varchar(255), + endpoint_last_seen timestamp ) INHERITS (assets); + ALTER TABLE endpoints + ADD CONSTRAINT endpoints_pkey PRIMARY KEY (asset_id) ; + """); + // Create table ips + select.execute(""" + CREATE TABLE IF NOT EXISTS ips ( + endpoint_id varchar(255) not null, + ip varchar(255) not null + ); + ALTER TABLE ips + ADD CONSTRAINT fk_ips_on_assets FOREIGN KEY (endpoint_id) REFERENCES endpoints(asset_id) ; + """); + // Create table mac adresses + select.execute(""" + CREATE TABLE IF NOT EXISTS macadresses ( + endpoint_id varchar(255) not null, + mac_adress varchar(255) not null + ); + ALTER TABLE macadresses + ADD CONSTRAINT fk_mac_adresses_on_assets FOREIGN KEY (endpoint_id) REFERENCES endpoints(asset_id) ; """); // Create table asset groups select.execute(""" 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 d1294867fa..31eb13774e 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 @@ -2,7 +2,7 @@ import io.openex.database.model.Endpoint; import io.openex.rest.asset.endpoint.form.EndpointInput; -import io.openex.service.asset.EndpointService; +import io.openex.service.AssetEndpointService; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; @@ -20,7 +20,7 @@ public class EndpointApi { public static final String ENDPOINT_URI = "/api/endpoints"; - private final EndpointService endpointService; + private final AssetEndpointService assetEndpointService; @PostMapping(ENDPOINT_URI) @RolesAllowed(ROLE_ADMIN) @@ -28,13 +28,13 @@ public Endpoint createEndpoint(@Valid @RequestBody final EndpointInput input) { Endpoint endpoint = new Endpoint(); endpoint.setUpdateAttributes(input); endpoint.setOs(Endpoint.OS_TYPE.valueOf(input.getOs())); - return this.endpointService.createEndpoint(endpoint); + return this.assetEndpointService.createEndpoint(endpoint); } @GetMapping(ENDPOINT_URI) @PreAuthorize("isObserver()") public List endpoints() { - return this.endpointService.endpoints(); + return this.assetEndpointService.endpoints(); } @PutMapping(ENDPOINT_URI + "/{endpointId}") @@ -42,15 +42,15 @@ public List endpoints() { public Endpoint updateEndpoint( @PathVariable @NotBlank final String endpointId, @Valid @RequestBody final EndpointInput input) { - Endpoint endpoint = this.endpointService.endpoint(endpointId); + Endpoint endpoint = this.assetEndpointService.endpoint(endpointId); endpoint.setUpdateAttributes(input); endpoint.setOs(Endpoint.OS_TYPE.valueOf(input.getOs())); - return this.endpointService.updateEndpoint(endpoint); + return this.assetEndpointService.updateEndpoint(endpoint); } @DeleteMapping(ENDPOINT_URI + "/{endpointId}") @RolesAllowed(ROLE_ADMIN) public void deleteEndpoint(@PathVariable @NotBlank final String endpointId) { - this.endpointService.deleteEndpoint(endpointId); + this.assetEndpointService.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 287ff26629..37d6547a7b 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 @@ -6,6 +6,8 @@ import lombok.EqualsAndHashCode; import javax.validation.constraints.NotBlank; +import java.time.Instant; +import java.util.List; import static io.openex.config.AppConfig.MANDATORY_MESSAGE; @@ -15,8 +17,8 @@ public class EndpointInput extends AssetInput { @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("endpoint_ip") - private String ip; + @JsonProperty("endpoint_ips") + private List ips; @JsonProperty("endpoint_hostname") private String hostname; @@ -25,4 +27,10 @@ public class EndpointInput extends AssetInput { @JsonProperty("endpoint_os") private String os; + @JsonProperty("endpoint_last_seen") + private Instant lastSeen; + + @JsonProperty("endpoint_mac_adresses") + private List macAdresses; + } diff --git a/openex-api/src/test/java/io/openex/rest/EndpointApiTest.java b/openex-api/src/test/java/io/openex/rest/EndpointApiTest.java index a3003b5ad5..3684c03c64 100644 --- a/openex-api/src/test/java/io/openex/rest/EndpointApiTest.java +++ b/openex-api/src/test/java/io/openex/rest/EndpointApiTest.java @@ -52,7 +52,7 @@ void createEndpointTest() throws Exception { EndpointInput endpointInput = new EndpointInput(); String name = "Personal PC"; endpointInput.setName(name); - endpointInput.setIp("127.0.0.1"); + endpointInput.setIps(List.of("127.0.0.1")); endpointInput.setHostname("hostname"); endpointInput.setOs(LINUX.name()); @@ -101,7 +101,7 @@ void updateEndpointTest() throws Exception { EndpointInput endpointInput = new EndpointInput(); String name = "Professional PC"; endpointInput.setName(name); - endpointInput.setIp(endpointResponse.getIp()); + endpointInput.setIps(endpointResponse.getIps()); endpointInput.setHostname(endpointResponse.getHostname()); endpointInput.setOs(endpointResponse.getOs().name()); diff --git a/openex-api/src/test/java/io/openex/service/EndpointServiceTest.java b/openex-api/src/test/java/io/openex/service/AssetEndpointServiceTest.java similarity index 72% rename from openex-api/src/test/java/io/openex/service/EndpointServiceTest.java rename to openex-api/src/test/java/io/openex/service/AssetEndpointServiceTest.java index a65f0a3a7f..27d6756788 100644 --- a/openex-api/src/test/java/io/openex/service/EndpointServiceTest.java +++ b/openex-api/src/test/java/io/openex/service/AssetEndpointServiceTest.java @@ -1,7 +1,6 @@ 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; @@ -15,10 +14,10 @@ @SpringBootTest @TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class EndpointServiceTest { +public class AssetEndpointServiceTest { @Autowired - private EndpointService endpointService; + private AssetEndpointService assetEndpointService; static String ENDPOINT_ID; @@ -30,14 +29,14 @@ void createEndpointFailedTest() { Endpoint endpoint = new Endpoint(); String name = "Personal PC"; endpoint.setName(name); - endpoint.setIp("wrong ip"); + endpoint.setIps(List.of("wrong ip")); endpoint.setHostname("hostname"); endpoint.setOs(LINUX); endpoint.setHostname("hostname"); endpoint.setOs(LINUX); // -- EXECUTE -- - assertThrows(TransactionSystemException.class, () -> this.endpointService.createEndpoint(endpoint)); + assertThrows(TransactionSystemException.class, () -> this.assetEndpointService.createEndpoint(endpoint)); } @DisplayName("Create endpoint succeed") @@ -48,14 +47,14 @@ void createEndpointSucceedTest() { Endpoint endpoint = new Endpoint(); String name = "Personal PC"; endpoint.setName(name); - endpoint.setIp("127.0.0.1"); + endpoint.setIps(List.of("127.0.0.1")); endpoint.setHostname("hostname"); endpoint.setOs(LINUX); endpoint.setHostname("hostname"); endpoint.setOs(LINUX); // -- EXECUTE -- - Endpoint endpointCreated = this.endpointService.createEndpoint(endpoint); + Endpoint endpointCreated = this.assetEndpointService.createEndpoint(endpoint); ENDPOINT_ID = endpointCreated.getId(); assertNotNull(endpointCreated); assertNotNull(endpointCreated.getId()); @@ -68,10 +67,10 @@ void createEndpointSucceedTest() { @Test @Order(3) void retrieveEndpointTest() { - Endpoint endpoint = this.endpointService.endpoint(ENDPOINT_ID); + Endpoint endpoint = this.assetEndpointService.endpoint(ENDPOINT_ID); assertNotNull(endpoint); - List endpoints = this.endpointService.endpoints(); + List endpoints = this.assetEndpointService.endpoints(); assertNotNull(endpoints); assertTrue(endpoints.stream().map(Endpoint::getId).toList().contains(ENDPOINT_ID)); } @@ -81,12 +80,12 @@ void retrieveEndpointTest() { @Order(4) void updateEndpointTest() { // -- PREPARE -- - Endpoint endpoint = this.endpointService.endpoint(ENDPOINT_ID); + Endpoint endpoint = this.assetEndpointService.endpoint(ENDPOINT_ID); String value = "Professional PC"; endpoint.setName(value); // -- EXECUTE -- - Endpoint endpointUpdated = this.endpointService.updateEndpoint(endpoint); + Endpoint endpointUpdated = this.assetEndpointService.updateEndpoint(endpoint); assertNotNull(endpoint); assertEquals(value, endpointUpdated.getName()); } @@ -95,8 +94,8 @@ void updateEndpointTest() { @Test @Order(5) void deleteEndpointTest() { - this.endpointService.deleteEndpoint(ENDPOINT_ID); - assertThrows(NoSuchElementException.class, () -> this.endpointService.endpoint(ENDPOINT_ID)); + this.assetEndpointService.deleteEndpoint(ENDPOINT_ID); + assertThrows(NoSuchElementException.class, () -> this.assetEndpointService.endpoint(ENDPOINT_ID)); } } 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 faf47cef6b..791683e575 100644 --- a/openex-api/src/test/java/io/openex/service/AssetGroupServiceTest.java +++ b/openex-api/src/test/java/io/openex/service/AssetGroupServiceTest.java @@ -2,7 +2,6 @@ import io.openex.database.model.Endpoint; 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; @@ -20,7 +19,7 @@ public class AssetGroupServiceTest { @Autowired private AssetGroupService assetGroupService; @Autowired - private EndpointService endpointService; + private AssetEndpointService assetEndpointService; static String ASSET_GROUP_ID; @@ -63,12 +62,12 @@ void updateAssetGroupTest() { Endpoint endpoint = new Endpoint(); String name = "Personal PC"; endpoint.setName(name); - endpoint.setIp("127.0.0.1"); + endpoint.setIps(List.of("127.0.0.1")); endpoint.setHostname("hostname"); endpoint.setOs(LINUX); endpoint.setHostname("hostname"); endpoint.setOs(LINUX); - Endpoint endpointCreated = this.endpointService.createEndpoint(endpoint); + Endpoint endpointCreated = this.assetEndpointService.createEndpoint(endpoint); AssetGroup assetGroup = this.assetGroupService.assetGroup(ASSET_GROUP_ID); String value = "Professional network"; diff --git a/openex-api/src/main/java/io/openex/service/asset/EndpointService.java b/openex-framework/src/main/java/io/openex/service/AssetEndpointService.java similarity index 82% rename from openex-api/src/main/java/io/openex/service/asset/EndpointService.java rename to openex-framework/src/main/java/io/openex/service/AssetEndpointService.java index f17016cd1e..d75c8bce15 100644 --- a/openex-api/src/main/java/io/openex/service/asset/EndpointService.java +++ b/openex-framework/src/main/java/io/openex/service/AssetEndpointService.java @@ -1,4 +1,4 @@ -package io.openex.service.asset; +package io.openex.service; import io.openex.database.model.Endpoint; import io.openex.database.repository.EndpointRepository; @@ -8,13 +8,14 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.util.List; +import java.util.Optional; import static io.openex.helper.StreamHelper.fromIterable; import static java.time.Instant.now; @RequiredArgsConstructor @Service -public class EndpointService { +public class AssetEndpointService { private final EndpointRepository endpointRepository; @@ -26,6 +27,10 @@ public Endpoint endpoint(@NotBlank final String endpointId) { return this.endpointRepository.findById(endpointId).orElseThrow(); } + public Optional endpointFromExternalId(@NotBlank final String externalId) { + return this.endpointRepository.findByExternalId(externalId); + } + public List endpoints() { return fromIterable(this.endpointRepository.findAll()); } 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 59658d6b09..9adec2cd70 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 @@ -7,7 +7,10 @@ import lombok.EqualsAndHashCode; import javax.persistence.*; -import javax.validation.constraints.NotBlank; +import java.time.Instant; +import java.util.List; + +import static java.time.Instant.now; @EqualsAndHashCode(callSuper = true) @Data @@ -21,11 +24,12 @@ public enum OS_TYPE { WINDOWS, } - @NotBlank @Ipv4OrIpv6Constraint - @Column(name = "endpoint_ip") - @JsonProperty("endpoint_ip") - private String ip; + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "ips", joinColumns = @JoinColumn(name = "endpoint_id")) + @Column(name = "ip") + @JsonProperty("endpoint_ips") + private List ips; @Column(name = "endpoint_hostname") @JsonProperty("endpoint_hostname") @@ -36,4 +40,14 @@ public enum OS_TYPE { @Enumerated(EnumType.STRING) private OS_TYPE os; + @Column(name = "endpoint_last_seen") + @JsonProperty("endpoint_last_seen") + private Instant lastSeen; + + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "macadresses", joinColumns = @JoinColumn(name = "endpoint_id")) + @Column(name = "mac_adress") + @JsonProperty("endpoint_mac_adresses") + private List macAdresses; + } 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 1b046b9dd7..8c96496bc3 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,8 +1,18 @@ package io.openex.database.repository; import io.openex.database.model.Endpoint; +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 javax.validation.constraints.NotBlank; +import java.util.Optional; + @Repository -public interface EndpointRepository extends CrudRepository { } +public interface EndpointRepository extends CrudRepository { + + @Query(value = "select e from Endpoint e where e.externalId = :externalId") + Optional findByExternalId(@NotBlank final @Param("externalId") String externalId); + +} 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 ce83d864f7..91c4745c43 100644 --- a/openex-model/src/main/java/io/openex/validator/Ipv4OrIpv6Validator.java +++ b/openex-model/src/main/java/io/openex/validator/Ipv4OrIpv6Validator.java @@ -5,13 +5,14 @@ import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; +import java.util.List; -public class Ipv4OrIpv6Validator implements ConstraintValidator { +public class Ipv4OrIpv6Validator implements ConstraintValidator> { @Override - public boolean isValid(final String ip, final ConstraintValidatorContext cxt) { + public boolean isValid(final List ips, final ConstraintValidatorContext cxt) { InetAddressValidator validator = InetAddressValidator.getInstance(); - return validator.isValid(ip); + return ips.stream().allMatch(validator::isValid); } }