Skip to content

Commit

Permalink
[backend/frontend] add architecture to executable payloads for filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
isselparra committed Oct 15, 2024
1 parent 43dc264 commit 93cf82a
Show file tree
Hide file tree
Showing 34 changed files with 320 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.openbas.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 V3_44__Add_column_executable_arch extends BaseJavaMigration {

@Override
public void migrate(Context context) throws Exception {
Connection connection = context.getConnection();
Statement statement = connection.createStatement();
statement.execute("ALTER TABLE payloads ADD executable_arch varchar(255);");
statement.execute("UPDATE payloads SET executable_arch = 'x86_64' WHERE payload_type ='Executable';");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import java.util.List;

@RestController
@RequestMapping("/api/atomic_testings")
@RequestMapping("/api/atomic-testings")
@PreAuthorize("isAdmin()")
@RequiredArgsConstructor
public class AtomicTestingApi extends RestBehavior {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ private void selectForInjectorContract(
injectorContractPayloadJoin.get("type").alias("payload_type"),
payloadCollectorJoin.get("type").alias("collector_type"),
injectorContractInjectorJoin.get("type").alias("injector_contract_injector_type"),
attackPatternIdsExpression.alias("injector_contract_attack_patterns")
attackPatternIdsExpression.alias("injector_contract_attack_patterns"),
injectorContractPayloadJoin.get("executableArch").alias("payload_executable_arch")
).distinct(true);

// GROUP BY
Expand All @@ -146,7 +147,8 @@ private List<InjectorContractOutput> execInjectorContract(TypedQuery<Tuple> quer
tuple.get("payload_type", String.class),
tuple.get("collector_type", String.class),
tuple.get("injector_contract_injector_type", String.class),
tuple.get("injector_contract_attack_patterns", String[].class)
tuple.get("injector_contract_attack_patterns", String[].class),
tuple.get("payload_executable_arch", Endpoint.PLATFORM_ARCH.class)
))
.toList();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.openbas.rest.injector_contract.output;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.openbas.database.model.Endpoint;
import io.openbas.database.model.Endpoint.PLATFORM_TYPE;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
Expand Down Expand Up @@ -33,6 +34,9 @@ public class InjectorContractOutput {
@JsonProperty("injector_contract_attack_patterns")
private List<String> attackPatterns;

@JsonProperty("injector_contract_arch")
private Endpoint.PLATFORM_ARCH arch;

public InjectorContractOutput(
String id,
Map<String, String> labels,
Expand All @@ -41,7 +45,8 @@ public InjectorContractOutput(
String payloadType,
String collectorType,
String injectorType,
String[] attackPatterns) {
String[] attackPatterns,
Endpoint.PLATFORM_ARCH arch) {
this.id = id;
this.labels = labels;
this.content = content;
Expand All @@ -50,5 +55,6 @@ public InjectorContractOutput(
this.injectorType = injectorType;

this.attackPatterns = attackPatterns != null ? new ArrayList<>(Arrays.asList(attackPatterns)) : new ArrayList<>();
this.arch = arch;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.openbas.rest.payload.form;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.openbas.database.model.Endpoint;
import io.openbas.database.model.Endpoint.PLATFORM_TYPE;
import io.openbas.database.model.Payload.PAYLOAD_SOURCE;
import io.openbas.database.model.Payload.PAYLOAD_STATUS;
Expand Down Expand Up @@ -50,6 +51,9 @@ public class PayloadCreateInput {
@JsonProperty("command_content")
private String content;

@JsonProperty("executable_arch")
private Endpoint.PLATFORM_ARCH executableArch;

@JsonProperty("executable_file")
private String executableFile;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.openbas.rest.payload.form;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.openbas.database.model.Endpoint;
import io.openbas.database.model.Endpoint.PLATFORM_TYPE;
import io.openbas.database.model.PayloadArgument;
import io.openbas.database.model.PayloadPrerequisite;
Expand Down Expand Up @@ -32,6 +33,9 @@ public class PayloadUpdateInput {
@JsonProperty("command_content")
private String content;

@JsonProperty("executable_arch")
private Endpoint.PLATFORM_ARCH executableArch;

Check warning on line 37 in openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadUpdateInput.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadUpdateInput.java#L37

Added line #L37 was not covered by tests

@JsonProperty("executable_file")
private String executableFile;

Expand Down
4 changes: 2 additions & 2 deletions openbas-api/src/main/java/io/openbas/schema/SchemaApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ public List<PropertySchemaDTO> schemas(
@RequestBody @Valid @NotNull List<String> filterNames) throws ClassNotFoundException {
String completeClassName = "io.openbas.database.model." + className;
if (filterableOnly) {
return SchemaUtils.schema(Class.forName(completeClassName))
return SchemaUtils.schemaWithSubtypes(Class.forName(completeClassName))

Check warning on line 26 in openbas-api/src/main/java/io/openbas/schema/SchemaApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/schema/SchemaApi.java#L26

Added line #L26 was not covered by tests
.stream()
.filter(PropertySchema::isFilterable)
.filter(p -> filterNames.isEmpty() || filterNames.contains(p.getJsonName()))
.map(PropertySchemaDTO::new)
.toList();
}
return SchemaUtils.schema(Class.forName(completeClassName))
return SchemaUtils.schemaWithSubtypes(Class.forName(completeClassName))

Check warning on line 33 in openbas-api/src/main/java/io/openbas/schema/SchemaApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/schema/SchemaApi.java#L33

Added line #L33 was not covered by tests
.stream()
.filter(p -> filterNames.isEmpty() || filterNames.contains(p.getJsonName()))
.map(PropertySchemaDTO::new)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public class InjectHelperTest {
void injectsToRunTest() {
// -- PREPARE --
Exercise exercise = new Exercise();
exercise.setName("Exercice name");
exercise.setName("Exercise name");
exercise.setStart(Instant.now());
exercise.setFrom("[email protected]");
exercise.setReplyTos(List.of("[email protected]"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class InjectCrudTest {
void createInjectSuccess() {
// -- PREPARE --
Exercise exercise = new Exercise();
exercise.setName("Exercice name");
exercise.setName("Exercise name");
exercise.setFrom("[email protected]");
exercise.setReplyTos(List.of("[email protected]"));
Exercise exerciseCreated = this.exerciseRepository.save(exercise);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class AtomicTestingApiTest extends IntegrationTest {

public static final String ATOMIC_TESTINGS_URI = "/api/atomic_testings";
public static final String ATOMIC_TESTINGS_URI = "/api/atomic-testings";

static Inject INJECT_WITH_PAYLOAD;
static Inject INJECT_WITHOUT_PAYLOAD;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
import java.util.ArrayList;
import java.util.List;

import static io.openbas.database.model.Endpoint.PLATFORM_ARCH.arm64;
import static io.openbas.database.model.Endpoint.PLATFORM_TYPE.Linux;
import static io.openbas.database.model.Filters.FilterOperator.contains;
import static io.openbas.database.model.Payload.PAYLOAD_SOURCE.MANUAL;
import static io.openbas.rest.payload.PayloadApi.PAYLOAD_URI;
import static io.openbas.utils.JsonUtils.asJsonString;
import static io.openbas.utils.fixtures.PayloadFixture.createDefaultCommand;
import static io.openbas.utils.fixtures.PayloadFixture.createDefaultDnsResolution;
import static io.openbas.utils.fixtures.PayloadFixture.*;
import static java.lang.String.valueOf;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
Expand All @@ -48,6 +48,10 @@ void beforeAll() {
Payload dnsResolution = createDefaultDnsResolution();
Payload dnsResolutionSaved = this.payloadRepository.save(dnsResolution);
PAYLOAD_COMMAND_IDS.add(dnsResolutionSaved.getId());

Payload executable = createDefaultExecutable();
Payload executableSaved = this.payloadRepository.save(executable);
PAYLOAD_COMMAND_IDS.add(executableSaved.getId());
}

@AfterAll
Expand Down Expand Up @@ -121,8 +125,9 @@ void given_sorting_input_by_updated_at_should_return_a_page_of_payloads_sort_by_
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(searchPaginationInput)))
.andExpect(status().is2xxSuccessful())
.andExpect(jsonPath("$.content.[0].payload_name").value("dns resolution payload"))
.andExpect(jsonPath("$.content.[1].payload_name").value("command payload"));
.andExpect(jsonPath("$.content.[0].payload_name").value("executable payload"))
.andExpect(jsonPath("$.content.[1].payload_name").value("dns resolution payload"))
.andExpect(jsonPath("$.content.[2].payload_name").value("command payload"));
}
}

Expand Down Expand Up @@ -169,7 +174,21 @@ void given_filter_input_by_source_should_return_a_page_of_payloads_filter_by_sou
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(searchPaginationInput)))
.andExpect(status().is2xxSuccessful())
.andExpect(jsonPath("$.numberOfElements").value(2));
.andExpect(jsonPath("$.numberOfElements").value(3));
}

@Test
@DisplayName("Filtering page of payloads by architecture")
void given_filter_input_by_arch_should_return_a_page_of_executable_payloads_filtered_by_architecture() throws Exception {
SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter(
"executable_arch", valueOf(arm64), contains
);

mvc.perform(post(PAYLOAD_URI + "/search")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(searchPaginationInput)))
.andExpect(status().is2xxSuccessful())
.andExpect(jsonPath("$.numberOfElements").value(1));
}

}
Expand Down
68 changes: 68 additions & 0 deletions openbas-api/src/test/java/io/openbas/rest/PayloadApiTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package io.openbas.rest;

import io.openbas.IntegrationTest;
import io.openbas.database.model.Document;
import io.openbas.database.model.Endpoint;
import io.openbas.database.model.Payload;
import io.openbas.database.repository.DocumentRepository;
import io.openbas.rest.payload.form.PayloadCreateInput;
import io.openbas.utils.mockUser.WithMockAdminUser;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import java.util.Collections;
import java.util.List;

import static io.openbas.utils.JsonUtils.asJsonString;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@TestInstance(PER_CLASS)
public class PayloadApiTest extends IntegrationTest {

private static final String PAYLOAD_URI = "/api/payloads";
private static Document EXECUTABLE_FILE;

@Autowired
private MockMvc mvc;
@Autowired
private DocumentRepository documentRepository;

@BeforeAll
void beforeAll() {
Document executableFile = new Document();
executableFile.setName("Executable file");
executableFile.setType("text/x-sh");
EXECUTABLE_FILE = documentRepository.save(executableFile);
}

@AfterAll
void afterAll() {
this.documentRepository.deleteAll(List.of(EXECUTABLE_FILE));
}
@Test
@DisplayName("Create Executable Payload")
@WithMockAdminUser
void createExecutablePayload() throws Exception {
PayloadCreateInput input = new PayloadCreateInput();
input.setType("Executable");
input.setName("My Executable Payload");
input.setSource(Payload.PAYLOAD_SOURCE.MANUAL);
input.setStatus(Payload.PAYLOAD_STATUS.VERIFIED);
input.setPlatforms(new Endpoint.PLATFORM_TYPE[]{Endpoint.PLATFORM_TYPE.Linux});
input.setAttackPatternsIds(Collections.emptyList());
input.setTagIds(Collections.emptyList());
input.setExecutableArch(Endpoint.PLATFORM_ARCH.x86_64);
input.setExecutableFile(EXECUTABLE_FILE.getId());

mvc.perform(post(PAYLOAD_URI)
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(input)))
.andExpect(status().is2xxSuccessful())
.andExpect(jsonPath("$.executable_arch").value("x86_64"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
import io.openbas.database.repository.*;
import io.openbas.rest.exercise.form.ExpectationUpdateInput;
import io.openbas.utils.fixtures.InjectExpectationFixture;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

Expand Down Expand Up @@ -57,6 +54,11 @@ void beforeAll() {
getInjectExpectation(injectCreated, teamCreated, exerciseCreated);
}

@AfterAll
void afterAll() {
this.exerciseRepository.deleteById(EXERCISE_ID);
}

@DisplayName("Retrieve inject expectations")
@Test
void retrieveInjectExpectations() {
Expand Down Expand Up @@ -86,7 +88,7 @@ void updateInjectExpectation() {

protected Exercise getExercise() {
Exercise exercise = new Exercise();
exercise.setName("Exercice name");
exercise.setName("Exercise name");
exercise.setStatus(SCHEDULED);
exercise.setFrom("[email protected]");
exercise.setReplyTos(List.of("[email protected]"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public class InjectTestStatusServiceTest {
@BeforeAll
void beforeAll() {
Exercise exercise = new Exercise();
exercise.setName("Exercice name");
exercise.setName("Exercise name");
exercise.setFrom("[email protected]");
exercise.setReplyTos(List.of("[email protected]"));
EXERCISE = this.exerciseRepository.save(exercise);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
import java.util.NoSuchElementException;

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;

@SpringBootTest
@TestInstance(PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class VariableServiceTest {

Expand All @@ -23,24 +25,32 @@ public class VariableServiceTest {
@Autowired
private ExerciseRepository exerciseRepository;

static String EXERCISE_ID;
static Exercise EXERCISE;
static String VARIABLE_ID;

@BeforeAll
void beforeAll() {
Exercise exercise = new Exercise();
exercise.setName("Exercise name");
exercise.setFrom("[email protected]");
exercise.setReplyTos(List.of("[email protected]"));
EXERCISE = this.exerciseRepository.save(exercise);
}

@AfterAll
void afterAll() {
this.exerciseRepository.deleteById(EXERCISE.getId());
}

@DisplayName("Create variable")
@Test
@Order(1)
void createVariableTest() {
// -- PREPARE --
Exercise exercise = new Exercise();
exercise.setName("Exercice name");
exercise.setFrom("[email protected]");
exercise.setReplyTos(List.of("[email protected]"));
Exercise exerciseCreated = this.exerciseRepository.save(exercise);
EXERCISE_ID = exerciseCreated.getId();
Variable variable = new Variable();
String variableKey = "key";
variable.setKey(variableKey);
variable.setExercise(exerciseCreated);
variable.setExercise(EXERCISE);

// -- EXECUTE --
Variable variableCreated = this.variableService.createVariable(variable);
Expand All @@ -60,7 +70,7 @@ void retrieveVariableTest() {
Variable variable = this.variableService.variable(VARIABLE_ID);
assertNotNull(variable);

List<Variable> variables = this.variableService.variablesFromExercise(EXERCISE_ID);
List<Variable> variables = this.variableService.variablesFromExercise(EXERCISE.getId());
assertNotNull(variable);
assertEquals(VARIABLE_ID, variables.get(0).getId());
}
Expand Down
Loading

0 comments on commit 93cf82a

Please sign in to comment.