FINERACT-1969 SQL Injection exception thrown even if no insecure string is in the input

This commit is contained in:
jmarta
2023-08-31 17:31:16 +02:00
committed by Adam Saghy
parent 28e9a62137
commit 6a90ce3f10
17 changed files with 636 additions and 906 deletions
@@ -718,19 +718,19 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder createDatatable(final String datatable, final Long apptableId, final Long datatableId) {
public CommandWrapperBuilder createDatatableEntry(final String datatable, final Long apptableId, final Long datatableId) {
this.actionName = "CREATE";
commonDatatableSettings(datatable, apptableId, datatableId);
return this;
}
public CommandWrapperBuilder updateDatatable(final String datatable, final Long apptableId, final Long datatableId) {
public CommandWrapperBuilder updateDatatableEntry(final String datatable, final Long apptableId, final Long datatableId) {
this.actionName = "UPDATE";
commonDatatableSettings(datatable, apptableId, datatableId);
return this;
}
public CommandWrapperBuilder deleteDatatable(final String datatable, final Long apptableId, final Long datatableId) {
public CommandWrapperBuilder deleteDatatableEntry(final String datatable, final Long apptableId, final Long datatableId) {
this.actionName = "DELETE";
commonDatatableSettings(datatable, apptableId, datatableId);
return this;
@@ -24,6 +24,7 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
@@ -78,6 +79,14 @@ public final class DateUtils {
return LocalDateTime.now(ZoneId.systemDefault()).truncatedTo(ChronoUnit.SECONDS);
}
public static LocalDateTime getAuditLocalDateTime() {
return LocalDateTime.now(ZoneId.of("UTC"));
}
public static OffsetDateTime getAuditOffsetDateTime() {
return OffsetDateTime.now(ZoneOffset.UTC);
}
public static boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(getBusinessLocalDate());
}
@@ -248,4 +248,19 @@ public class DatabaseSpecificSQLGenerator {
return orderBy + orders.stream().map(e -> String.join(" ", alias(escape(e.getProperty()), alias), e.getDirection().name()))
.collect(Collectors.joining(", "));
}
public String buildInsert(@NotNull String definition, Collection<String> fields) {
if (fields == null || fields.isEmpty()) {
return "";
}
return "INSERT INTO " + escape(definition) + '(' + fields.stream().map(this::escape).collect(Collectors.joining(", "))
+ ") VALUES (?" + ", ?".repeat(fields.size() - 1) + ')';
}
public String buildUpdate(@NotNull String definition, Collection<String> fields) {
if (fields == null || fields.isEmpty()) {
return "";
}
return "UPDATE " + escape(definition) + " SET " + fields.stream().map(e -> escape(e) + " = ?").collect(Collectors.joining(", "));
}
}
@@ -314,7 +314,7 @@ public class DatatablesApiResource {
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.createDatatable(datatable, apptableId, null) //
.createDatatableEntry(datatable, apptableId, null) //
.withJson(apiRequestBodyAsJson) //
.build();
@@ -336,7 +336,7 @@ public class DatatablesApiResource {
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.updateDatatable(datatable, apptableId, null) //
.updateDatatableEntry(datatable, apptableId, null) //
.withJson(apiRequestBodyAsJson) //
.build();
@@ -359,7 +359,7 @@ public class DatatablesApiResource {
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.updateDatatable(datatable, apptableId, datatableId) //
.updateDatatableEntry(datatable, apptableId, datatableId) //
.withJson(apiRequestBodyAsJson) //
.build();
@@ -380,7 +380,7 @@ public class DatatablesApiResource {
@PathParam("apptableId") @Parameter(description = "apptableId") final Long apptableId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.deleteDatatable(datatable, apptableId, null) //
.deleteDatatableEntry(datatable, apptableId, null) //
.build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
@@ -396,13 +396,11 @@ public class DatatablesApiResource {
+ "\n")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DatatablesApiResourceSwagger.DeleteDataTablesDatatableAppTableIdDatatableIdResponse.class))) })
public String deleteDatatableEntries(
@PathParam("datatable") @Parameter(description = "datatable", example = "{}") final String datatable,
public String deleteDatatableEntry(@PathParam("datatable") @Parameter(description = "datatable", example = "{}") final String datatable,
@PathParam("apptableId") @Parameter(description = "apptableId") final Long apptableId,
@PathParam("datatableId") @Parameter(description = "datatableId") final Long datatableId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.deleteDatatable(datatable, apptableId, datatableId) //
.deleteDatatableEntry(datatable, apptableId, datatableId) //
.build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
@@ -21,7 +21,6 @@ package org.apache.fineract.infrastructure.dataqueries.handler;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.dataqueries.service.ReadWriteNonCoreDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -40,18 +39,6 @@ public class DeleteOneToManyDatatableEntryCommandHandler implements NewCommandSo
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
final CommandProcessingResult commandProcessingResult = this.writePlatformService.deleteDatatableEntry(command.entityName(),
command.entityId(), command.subentityId());
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(command.entityId()) //
.withOfficeId(commandProcessingResult.getOfficeId()) //
.withGroupId(commandProcessingResult.getGroupId()) //
.withClientId(commandProcessingResult.getClientId()) //
.withSavingsId(commandProcessingResult.getSavingsId()) //
.withLoanId(commandProcessingResult.getLoanId()) //
.build();
return this.writePlatformService.deleteDatatableEntry(command.entityName(), command.entityId(), command.subentityId(), command);
}
}
@@ -21,7 +21,6 @@ package org.apache.fineract.infrastructure.dataqueries.handler;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.dataqueries.service.ReadWriteNonCoreDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -40,18 +39,6 @@ public class DeleteOneToOneDatatableEntryCommandHandler implements NewCommandSou
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
final CommandProcessingResult commandProcessingResult = this.writePlatformService.deleteDatatableEntries(command.entityName(),
command.entityId());
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(command.entityId()) //
.withOfficeId(commandProcessingResult.getOfficeId()) //
.withGroupId(commandProcessingResult.getGroupId()) //
.withClientId(commandProcessingResult.getClientId()) //
.withSavingsId(commandProcessingResult.getSavingsId()) //
.withLoanId(commandProcessingResult.getLoanId()) //
.build();
return this.writePlatformService.deleteDatatableEntries(command.entityName(), command.entityId(), command);
}
}
@@ -272,5 +272,4 @@ public class EntityDatatableChecksWritePlatformServiceImpl implements EntityData
throw new PlatformDataIntegrityException("error.msg.report.unknown.data.integrity.issue",
"Unknown data integrity issue with resource: " + realCause.getMessage());
}
}
@@ -68,9 +68,9 @@ public interface ReadWriteNonCoreDataService {
CommandProcessingResult updateDatatableEntryOneToMany(String datatable, Long appTableId, Long datatableId, JsonCommand command);
CommandProcessingResult deleteDatatableEntries(String datatable, Long appTableId);
CommandProcessingResult deleteDatatableEntries(String datatable, Long appTableId, JsonCommand command);
CommandProcessingResult deleteDatatableEntry(String datatable, Long appTableId, Long datatableId);
CommandProcessingResult deleteDatatableEntry(String datatable, Long appTableId, Long datatableId, JsonCommand command);
String getTableName(String Url);
@@ -174,7 +174,7 @@ public class SurveyApiResource {
@PathParam("fulfilledId") final Long fulfilledId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.deleteDatatable(surveyName, clientId, fulfilledId) //
.deleteDatatableEntry(surveyName, clientId, fulfilledId) //
.build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
@@ -31,6 +31,9 @@ public final class SearchConstants {
public static final String API_PARAM_VALUES = "values";
public static final String API_PARAM_TABLE = "table";
public static final String API_PARAM_QUERY = "query";
public static final String API_PARAM_DATE_FORMAT = "dateFormat";
public static final String API_PARAM_DATETIME_FORMAT = "dateTimeFormat";
public static final String API_PARAM_LOCALE = "locale";
private SearchConstants() {}
@@ -86,8 +86,7 @@ public final class SearchUtil {
@NotNull List<String> resultColumns, @NotNull List<JsonObject> results) {
JsonObject json = new JsonObject();
for (int i = 0; i < selectColumns.size(); i++) {
String sCol = selectColumns.get(i).replaceAll("\"", "");
Object rowValue = rowSet.getObject(sCol);
Object rowValue = rowSet.getObject(selectColumns.get(i));
if (rowValue != null) {
String rCol = resultColumns.get(i);
if (rowValue instanceof Character) {
@@ -178,7 +178,8 @@ public class SavingsAccountTransactionDatatableIntegrationTest {
assertNotNull(response);
String datatableId = response.getResourceIdentifier();
String createdName = response.getResourceIdentifier();
assertEquals(datatableName, createdName);
// add entries
final HashMap<String, Object> datatableEntryMap = new HashMap<>();
@@ -190,13 +191,14 @@ public class SavingsAccountTransactionDatatableIntegrationTest {
final boolean genericResultSet = true;
HashMap<String, Object> datatableEntryResponseFirst = this.datatableHelper.createDatatableEntry(datatableId, transactionId,
HashMap<String, Object> datatableEntryResponseFirst = this.datatableHelper.createDatatableEntry(datatableName, transactionId,
genericResultSet, datatabelEntryRequestJsonString);
assertNotNull(datatableEntryResponseFirst.get("resourceId"));
Integer datatableId = (Integer) datatableEntryResponseFirst.get("resourceId");
assertNotNull(datatableId);
// Read the Datatable entry generated with genericResultSet
HashMap<String, Object> items = this.datatableHelper.readDatatableEntry(datatableId, transactionId, genericResultSet, null, "");
HashMap<String, Object> items = this.datatableHelper.readDatatableEntry(datatableName, transactionId, genericResultSet, null, "");
assertNotNull(items);
assertEquals(1, ((List) items.get("data")).size());
@@ -206,13 +208,14 @@ public class SavingsAccountTransactionDatatableIntegrationTest {
datatableEntryMap.put("dateFormat", "yyyy-MM-dd");
datatabelEntryRequestJsonString = new Gson().toJson(datatableEntryMap);
HashMap<String, Object> updatedDatatableEntryResponse = this.datatableHelper.updateDatatableEntry(datatableName, transactionId,
false, datatabelEntryRequestJsonString);
datatableId, false, datatabelEntryRequestJsonString);
assertEquals(transactionId, updatedDatatableEntryResponse.get("resourceId"));
assertEquals(transactionId, Integer.valueOf((String) updatedDatatableEntryResponse.get("transactionId")));
assertEquals(datatableId, updatedDatatableEntryResponse.get("resourceId"));
// deleting datatable entries
Integer appTableId = this.datatableHelper.deleteDatatableEntries(datatableName, transactionId, "resourceId");
assertEquals(transactionId, appTableId, "ERROR IN DELETING THE DATATABLE ENTRIES");
String deletedTransactionId = (String) this.datatableHelper.deleteDatatableEntries(datatableName, transactionId, "transactionId");
assertEquals(transactionId, Integer.valueOf(deletedTransactionId), "ERROR IN DELETING THE DATATABLE ENTRIES");
// deleting the datatable
String deletedDataTableName = this.datatableHelper.deleteDatatable(datatableName);
@@ -155,7 +155,7 @@ public class EntityDatatableChecksIntegrationTest {
assertNotNull(entityDatatableCheckId, "ERROR IN DELETING THE ENTITY DATATABLE CHECK");
// deleting datatable entries
Integer appTableId = this.datatableHelper.deleteDatatableEntries(registeredTableName, clientID, "clientId");
Integer appTableId = (Integer) this.datatableHelper.deleteDatatableEntries(registeredTableName, clientID, "clientId");
assertEquals(clientID, appTableId, "ERROR IN DELETING THE DATATABLE ENTRIES");
// deleting the datatable
@@ -215,7 +215,7 @@ public class EntityDatatableChecksIntegrationTest {
assertNotNull(entityDatatableCheckId, "ERROR IN DELETING THE ENTITY DATATABLE CHECK");
// deleting datatable entries
Integer appTableId = this.datatableHelper.deleteDatatableEntries(registeredTableName, groupId, "groupId");
Integer appTableId = (Integer) this.datatableHelper.deleteDatatableEntries(registeredTableName, groupId, "groupId");
assertEquals(groupId, appTableId, "ERROR IN DELETING THE DATATABLE ENTRIES");
// deleting the datatable
@@ -290,7 +290,7 @@ public class EntityDatatableChecksIntegrationTest {
assertNotNull(entityDatatableCheckId, "ERROR IN DELETING THE ENTITY DATATABLE CHECK");
// deleting datatable entries
Integer appTableId = this.datatableHelper.deleteDatatableEntries(registeredTableName, savingsId, "savingsId");
Integer appTableId = (Integer) this.datatableHelper.deleteDatatableEntries(registeredTableName, savingsId, "savingsId");
assertEquals(savingsId, appTableId, "ERROR IN DELETING THE DATATABLE ENTRIES");
// deleting the datatable
@@ -372,7 +372,7 @@ public class EntityDatatableChecksIntegrationTest {
assertNotNull(entityDatatableCheckId, "ERROR IN DELETING THE ENTITY DATATABLE CHECK");
// deleting datatable entries
Integer appTableId = this.datatableHelper.deleteDatatableEntries(registeredTableName, loanID, "loanId");
Integer appTableId = (Integer) this.datatableHelper.deleteDatatableEntries(registeredTableName, loanID, "loanId");
assertEquals(loanID, appTableId, "ERROR IN DELETING THE DATATABLE ENTRIES");
// deleting the datatable
@@ -155,7 +155,7 @@ public class DatatableHelper extends IntegrationTest {
DATATABLE_URL + "/" + datatableName + "?" + Utils.TENANT_IDENTIFIER, "resourceIdentifier");
}
public Integer deleteDatatableEntries(final String datatableName, final Integer apptableId, String jsonAttributeToGetBack) {
public Object deleteDatatableEntries(final String datatableName, final Integer apptableId, String jsonAttributeToGetBack) {
final String deleteEntryUrl = DATATABLE_URL + "/" + datatableName + "/" + apptableId + "?genericResultSet=true" + "&"
+ Utils.TENANT_IDENTIFIER;
return Utils.performServerDelete(this.requestSpec, this.responseSpec, deleteEntryUrl, jsonAttributeToGetBack);
@@ -359,8 +359,8 @@ public class DatatableAdvancedQueryTest {
private void deleteDatatable(String datatable, Integer... apptableIds) {
for (Integer apptableId : apptableIds) {
Integer deletedId = this.datatableHelper.deleteDatatableEntries(datatable, apptableId, "resourceId");
assertEquals(apptableId, deletedId, "ERROR IN DELETING THE DATATABLE ENTRY");
String deletedId = (String) this.datatableHelper.deleteDatatableEntries(datatable, apptableId, "transactionId");
assertEquals(apptableId, Integer.valueOf(deletedId), "ERROR IN DELETING THE DATATABLE ENTRY");
}
String deletedDatatable = this.datatableHelper.deleteDatatable(datatable);
assertEquals(datatable, deletedDatatable, "ERROR IN DELETING THE DATATABLE");
@@ -333,7 +333,7 @@ public class DatatableIntegrationTest extends IntegrationTest {
}
// deleting datatable entries
Integer appTableId = this.datatableHelper.deleteDatatableEntries(datatableName, clientID, "clientId");
Integer appTableId = (Integer) this.datatableHelper.deleteDatatableEntries(datatableName, clientID, "clientId");
assertEquals(clientID, appTableId, "ERROR IN DELETING THE DATATABLE ENTRIES");
// deleting the datatable
@@ -434,7 +434,7 @@ public class DatatableIntegrationTest extends IntegrationTest {
LOG.info("query result : {}", queryResult);
// deleting datatable entries
Integer appTableId = this.datatableHelper.deleteDatatableEntries(datatableName, clientID, "clientId");
Integer appTableId = (Integer) this.datatableHelper.deleteDatatableEntries(datatableName, clientID, "clientId");
assertEquals(clientID, appTableId, "ERROR IN DELETING THE DATATABLE ENTRIES");
// deleting the datatable
@@ -662,7 +662,7 @@ public class DatatableIntegrationTest extends IntegrationTest {
assertEquals(randomString, records.get(2));
assertEquals(textValue, records.get(5));
Integer resourceId = this.datatableHelper.deleteDatatableEntries(datatableName, clientId, "resourceId");
Integer resourceId = (Integer) this.datatableHelper.deleteDatatableEntries(datatableName, clientId, "resourceId");
assertEquals(clientId, resourceId, "ERROR IN DELETING THE DATATABLE ENTRIES");
// Update - update, delete DataTable columns
@@ -915,7 +915,7 @@ public class DatatableIntegrationTest extends IntegrationTest {
assertEquals(datatableEntryMap.get("itsAText"), datatableEntryResponseNoGenericResult.get(0).get("itsAText"));
// deleting datatable entries
Integer appTableId = this.datatableHelper.deleteDatatableEntries(datatableName, loanID, "loanId");
Integer appTableId = (Integer) this.datatableHelper.deleteDatatableEntries(datatableName, loanID, "loanId");
assertEquals(loanID, appTableId, "ERROR IN DELETING THE DATATABLE ENTRIES");
// deleting the datatable