Merge pull request #483 from ShruthiRajaram/sqlFix

sql fix
This commit is contained in:
ShruthiRajaram
2018-12-18 15:01:18 +05:30
committed by GitHub
9 changed files with 115 additions and 61 deletions
@@ -50,6 +50,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -177,10 +178,13 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
}
private void validateForAttachedProduct(Long glAccountId) {
String sql = "select count(*) from acc_product_mapping acc where acc.gl_account_id = "+glAccountId;
int count = this.jdbcTemplate.queryForObject(sql, Integer.class);
if(count>0){
throw new GLAccountDisableException();
String sql = "select count(*) from acc_product_mapping acc where acc.gl_account_id = ?";
try {
int count = this.jdbcTemplate.queryForObject(sql, Integer.class, glAccountId);
if (count > 0) {
throw new GLAccountDisableException();
}
} catch (EmptyResultDataAccessException e) {
}
}
@@ -85,10 +85,10 @@ public class CreditBureauReadConfigurationServiceImpl implements CreditBureauRea
this.context.authenticatedUser();
final CbConfigMapper rm = new CbConfigMapper();
final String sql = "select " + rm.schema() + " where cbconfig.organisation_creditbureau_id=" + id;
final String sql = "select " + rm.schema() + " where cbconfig.organisation_creditbureau_id= ?";
List<CreditBureauConfigurationData> config = (List<CreditBureauConfigurationData>) this.jdbcTemplate.query(sql,
rm, new Object[] {});
rm, new Object[] {id});
Map<String, String> configuration = new HashMap<String, String>();
for (CreditBureauConfigurationData data : config) {
configuration.put(data.getConfigurationKey(), data.getValue());
@@ -49,6 +49,7 @@ import org.apache.fineract.infrastructure.report.provider.ReportingProcessServic
import org.apache.fineract.infrastructure.report.service.ReportingProcessService;
import org.apache.fineract.infrastructure.security.exception.NoAuthorizationException;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
@@ -177,6 +178,7 @@ public class RunreportsApiResource {
if (k.startsWith("R_")) {
pKey = "${" + k.substring(2) + "}";
pValue = queryParams.get(k).get(0);
SQLInjectionValidator.validateSQLInput(pValue);
reportParams.put(pKey, pValue);
}
}
@@ -23,10 +23,11 @@ import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourc
/**
* A {@link RuntimeException} thrown when report resources are not found.
*/
@SuppressWarnings("serial")
public class ReportNotFoundException extends AbstractPlatformResourceNotFoundException {
public ReportNotFoundException(final String reportSql) {
super("error.msg.report.name.not.found", "Reporting meta-data entry not found.", "Input sql: " + reportSql);
public ReportNotFoundException(final String reportName) {
super("error.msg.report.name.not.found", "Reporting meta-data entry not found.", "Report Name: " + reportName);
}
public ReportNotFoundException(final Long id) {
@@ -23,6 +23,7 @@ import java.util.List;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
@@ -34,6 +35,7 @@ import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;
@@ -55,37 +57,40 @@ public class GenericDataServiceImpl implements GenericDataService {
@Override
public GenericResultsetData fillGenericResultSet(final String sql) {
try{
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
final List<ResultsetColumnHeaderData> columnHeaders = new ArrayList<>();
final List<ResultsetRowData> resultsetDataRows = new ArrayList<>();
final List<ResultsetColumnHeaderData> columnHeaders = new ArrayList<>();
final List<ResultsetRowData> resultsetDataRows = new ArrayList<>();
final SqlRowSetMetaData rsmd = rs.getMetaData();
final SqlRowSetMetaData rsmd = rs.getMetaData();
for (int i = 0; i < rsmd.getColumnCount(); i++) {
for (int i = 0; i < rsmd.getColumnCount(); i++) {
final String columnName = rsmd.getColumnName(i + 1);
final String columnType = rsmd.getColumnTypeName(i + 1);
final String columnName = rsmd.getColumnName(i + 1);
final String columnType = rsmd.getColumnTypeName(i + 1);
final ResultsetColumnHeaderData columnHeader = ResultsetColumnHeaderData.basic(columnName, columnType);
columnHeaders.add(columnHeader);
}
final ResultsetColumnHeaderData columnHeader = ResultsetColumnHeaderData.basic(columnName, columnType);
columnHeaders.add(columnHeader);
}
while (rs.next()) {
final List<String> columnValues = new ArrayList<>();
for (int i = 0; i < rsmd.getColumnCount(); i++) {
final String columnName = rsmd.getColumnName(i + 1);
final String columnValue = rs.getString(columnName);
columnValues.add(columnValue);
}
while (rs.next()) {
final List<String> columnValues = new ArrayList<>();
for (int i = 0; i < rsmd.getColumnCount(); i++) {
final String columnName = rsmd.getColumnName(i + 1);
final String columnValue = rs.getString(columnName);
columnValues.add(columnValue);
}
final ResultsetRowData resultsetDataRow = ResultsetRowData.create(columnValues);
resultsetDataRows.add(resultsetDataRow);
}
final ResultsetRowData resultsetDataRow = ResultsetRowData.create(columnValues);
resultsetDataRows.add(resultsetDataRow);
}
return new GenericResultsetData(columnHeaders, resultsetDataRows);
}
return new GenericResultsetData(columnHeaders, resultsetDataRows);
} catch (DataAccessException e) {
throw new PlatformDataIntegrityException("error.msg.report.unknown.data.integrity.issue", e.getClass().getName());
}
}
@Override
public String replace(final String str, final String pattern, final String replace) {
@@ -36,6 +36,7 @@ import java.util.Set;
import javax.sql.DataSource;
import javax.ws.rs.core.StreamingOutput;
import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
@@ -50,6 +51,7 @@ import org.apache.fineract.infrastructure.documentmanagement.contentrepository.F
import org.apache.fineract.infrastructure.report.provider.ReportingProcessServiceProvider;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.infrastructure.security.utils.SQLInjectionException;
import org.apache.fineract.useradministration.domain.AppUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -68,6 +70,7 @@ import com.lowagie.text.pdf.PdfWriter;
public class ReadReportingServiceImpl implements ReadReportingService {
private final static Logger logger = LoggerFactory.getLogger(ReadReportingServiceImpl.class);
private final static String REPORT_NAME_REGEX_PATTERN = "^[a-zA-Z][a-zA-Z0-9\\-_\\s]{0,48}[a-zA-Z0-9]$";
private final JdbcTemplate jdbcTemplate;
private final DataSource dataSource;
@@ -218,20 +221,24 @@ public class ReadReportingServiceImpl implements ReadReportingService {
private String getSql(final String name, final String type) {
final String inputSql = "select " + type + "_sql as the_sql from stretchy_" + type + " where " + type + "_name = '" + name + "'" ;
final String inputSql = "select " + type + "_sql as the_sql from stretchy_" + type + " where " + type + "_name = '" + name + "'";
validateReportName(name);
this.columnValidator.validateSqlInjection(inputSql, name);
final String inputSqlWrapped = this.genericDataService.wrapSQL(inputSql);
// the return statement contains the exact sql required
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(inputSqlWrapped);
if (rs.next() && rs.getString("the_sql") != null) { return rs.getString("the_sql"); }
throw new ReportNotFoundException(inputSql);
throw new ReportNotFoundException(name);
}
@Override
public String getReportType(final String reportName, final boolean isSelfServiceUserReport) {
final String sql = "SELECT ifnull(report_type,'') as report_type FROM `stretchy_report` where report_name = '" + reportName + "' and self_service_user_report = ?";
validateReportName(reportName);
this.columnValidator.validateSqlInjection(sql, reportName);
final String sqlWrapped = this.genericDataService.wrapSQL(sql);
@@ -239,7 +246,7 @@ public class ReadReportingServiceImpl implements ReadReportingService {
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sqlWrapped, new Object [] {isSelfServiceUserReport});
if (rs.next()) { return rs.getString("report_type"); }
throw new ReportNotFoundException(sql);
throw new ReportNotFoundException(reportName);
}
@Override
@@ -453,7 +460,7 @@ public class ReadReportingServiceImpl implements ReadReportingService {
}
@Override
public ReportParameterJoinData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
public ReportParameterJoinData mapRow(final ResultSet rs, final int rowNum) throws SQLException {
final Long reportId = rs.getLong("reportId");
final String reportName = rs.getString("reportName");
@@ -491,7 +498,7 @@ public class ReadReportingServiceImpl implements ReadReportingService {
}
@Override
public ReportParameterData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
public ReportParameterData mapRow(final ResultSet rs, final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String parameterName = rs.getString("parameterName");
@@ -610,6 +617,11 @@ public class ReadReportingServiceImpl implements ReadReportingService {
*/
return null ;
}
private void validateReportName(final String name) {
if (!StringUtils.isBlank(name) && !name.matches(REPORT_NAME_REGEX_PATTERN)) {
throw new SQLInjectionException();
}
}
}
@@ -20,7 +20,13 @@ package org.apache.fineract.infrastructure.dataqueries.service;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
@@ -44,7 +50,11 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant;
import org.apache.fineract.infrastructure.dataqueries.data.*;
import org.apache.fineract.infrastructure.dataqueries.data.DataTableValidator;
import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
import org.apache.fineract.infrastructure.dataqueries.data.ResultsetRowData;
import org.apache.fineract.infrastructure.dataqueries.exception.DatatableEntryRequiredException;
import org.apache.fineract.infrastructure.dataqueries.exception.DatatableNotFoundException;
import org.apache.fineract.infrastructure.dataqueries.exception.DatatableSystemErrorException;
@@ -62,6 +72,7 @@ import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;
import org.springframework.stereotype.Service;
@@ -108,6 +119,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
private final CodeReadPlatformService codeReadPlatformService;
private final DataTableValidator dataTableValidator;
private final ColumnValidator columnValidator;
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
// private final GlobalConfigurationWritePlatformServiceJpaRepositoryImpl
// configurationWriteService;
@@ -130,6 +142,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
this.dataTableValidator = dataTableValidator;
this.columnValidator = columnValidator;
// this.configurationWriteService = configurationWriteService;
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
@Override
@@ -139,6 +152,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (appTable == null) {
andClause = "";
} else {
validateAppTable(appTable);
SQLInjectionValidator.validateSQLInput(appTable);
andClause = " and application_table_name = '" + appTable + "'";
}
@@ -225,7 +239,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
@Transactional
@Override
public void registerDatatable(final JsonCommand command, final String permissionSql) {
public void registerDatatable(final JsonCommand command, final String permissionSql) {
final String applicationTableName = this.getTableName(command.getUrl());
final String dataTableName = this.getDataTableName(command.getUrl());
@@ -237,24 +251,27 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
@Transactional
@Transactional
private void _registerDataTable(final String applicationTableName, final String dataTableName, final Integer category,
final String permissionsSql) {
validateAppTable(applicationTableName);
validateDatatableName(dataTableName);
assertDataTableExists(dataTableName);
final String registerDatatableSql = "insert into x_registered_table (registered_table_name, application_table_name,category) values ('"
+ dataTableName + "', '" + applicationTableName + "', '" + category + "')";
Map<String, Object> paramMap = new HashMap<>(3);
final String registerDatatableSql = "insert into x_registered_table (registered_table_name, application_table_name,category) values ( :dataTableName, :applicationTableName, :category)";
paramMap.put("dataTableName", dataTableName);
paramMap.put("applicationTableName", applicationTableName);
paramMap.put("category", category);
try {
final String[] sqlArray = { registerDatatableSql, permissionsSql };
this.jdbcTemplate.batchUpdate(sqlArray);
this.namedParameterJdbcTemplate.update(registerDatatableSql, paramMap);
this.jdbcTemplate.update(permissionsSql);
// add the registered table to the config if it is a ppi
if (this.isSurveyCategory(category)) {
this.jdbcTemplate.execute("insert into c_configuration (name, value, enabled ) values('" + dataTableName + "', '0','0')");
this.namedParameterJdbcTemplate.update("insert into c_configuration (name, value, enabled ) values( :dataTableName , '0','0')", paramMap);
}
}
@@ -333,6 +350,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
@Transactional
@Override
public void deregisterDatatable(final String datatable) {
validateDatatableName(datatable);
final String permissionList = "('CREATE_" + datatable + "', 'CREATE_" + datatable + "_CHECKER', 'READ_" + datatable + "', 'UPDATE_"
+ datatable + "', 'UPDATE_" + datatable + "_CHECKER', 'DELETE_" + datatable + "', 'DELETE_" + datatable + "_CHECKER')";
@@ -476,6 +494,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
throw new PlatformDataIntegrityException("error.msg.datatables.datatable.null.name", "Data table name must not be blank.");
} else if (!name.matches(DATATABLE_NAME_REGEX_PATTERN)) { throw new PlatformDataIntegrityException(
"error.msg.datatables.datatable.invalid.name.regex", "Invalid data table name.", name); }
SQLInjectionValidator.validateSQLInput(name);
}
private String datatableColumnNameToCodeValueName(final String columnName, final String code) {
@@ -1141,6 +1160,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
@Override
public CommandProcessingResult deleteDatatableEntries(final String dataTableName, final Long appTableId) {
validateDatatableName(dataTableName);
if (isDatatableAttachedToEntityDatatableCheck(dataTableName)) { throw new DatatableEntryRequiredException(dataTableName, appTableId); }
final String appTable = queryForApplicationTableName(dataTableName);
final CommandProcessingResult commandProcessingResult = checkMainResourceExistsWithinScope(appTable, appTableId);
@@ -1155,6 +1175,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
@Transactional
@Override
public CommandProcessingResult deleteDatatableEntry(final String dataTableName, final Long appTableId, final Long datatableId) {
validateDatatableName(dataTableName);
if (isDatatableAttachedToEntityDatatableCheck(dataTableName)) { throw new DatatableEntryRequiredException(dataTableName, appTableId); }
final String appTable = queryForApplicationTableName(dataTableName);
final CommandProcessingResult commandProcessingResult = checkMainResourceExistsWithinScope(appTable, appTableId);
@@ -115,14 +115,18 @@ public class SchedulerJobRunnerReadServiceImpl implements SchedulerJobRunnerRead
}
private boolean isJobExist(final Long jobId) {
boolean isJobPresent = false;
final String sql = "select count(*) from job job where job.id=" + jobId;
@SuppressWarnings("deprecation")
final int count = this.jdbcTemplate.queryForInt(sql);
if (count == 1) {
isJobPresent = true;
}
return isJobPresent;
boolean isJobPresent = false;
try{
final String sql = "select count(*) from job job where job.id= ?";
final int count = this.jdbcTemplate.queryForObject(sql, Integer.class, new Object[] { jobId });
if (count == 1) {
isJobPresent = true;
}
return isJobPresent;
}catch(EmptyResultDataAccessException e){
return isJobPresent;
}
}
private static final class JobDetailMapper implements RowMapper<JobDetailData> {
@@ -33,6 +33,7 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -214,9 +215,10 @@ public class AdHocQueryDataValidator {
final JsonElement element = this.fromApiJsonHelper.parse(json);
List<String> loanStatus = null;
if (this.fromApiJsonHelper.parameterExists(AdHocQuerySearchConstants.loanStatusParamName, element)) {
loanStatus = Arrays.asList(this.fromApiJsonHelper.extractArrayNamed(AdHocQuerySearchConstants.loanStatusParamName, element));
}
if (this.fromApiJsonHelper.parameterExists(AdHocQuerySearchConstants.loanStatusParamName, element)) {
loanStatus = Arrays.asList(
this.fromApiJsonHelper.extractArrayNamed(AdHocQuerySearchConstants.loanStatusParamName, element));
}
List<Long> loanProducts = null;
if (this.fromApiJsonHelper.parameterExists(AdHocQuerySearchConstants.loanProductsParamName, element)) {
@@ -233,6 +235,7 @@ public class AdHocQueryDataValidator {
String loanDateOption = null;
if (this.fromApiJsonHelper.parameterExists(AdHocQuerySearchConstants.loanDateOptionParamName, element)) {
loanDateOption = this.fromApiJsonHelper.extractStringNamed(AdHocQuerySearchConstants.loanDateOptionParamName, element);
SQLInjectionValidator.validateSQLInput(loanDateOption);
}
LocalDate loanFromDate = null;
@@ -255,6 +258,7 @@ public class AdHocQueryDataValidator {
if (this.fromApiJsonHelper.parameterExists(AdHocQuerySearchConstants.outStandingAmountPercentageConditionParamName, element)) {
outStandingAmountPercentageCondition = this.fromApiJsonHelper.extractStringNamed(
AdHocQuerySearchConstants.outStandingAmountPercentageConditionParamName, element);
SQLInjectionValidator.validateSQLInput(outStandingAmountPercentageCondition);
}
BigDecimal minOutStandingAmountPercentage = null;
@@ -285,6 +289,7 @@ public class AdHocQueryDataValidator {
if (this.fromApiJsonHelper.parameterExists(AdHocQuerySearchConstants.outstandingAmountConditionParamName, element)) {
outstandingAmountCondition = this.fromApiJsonHelper.extractStringNamed(
AdHocQuerySearchConstants.outstandingAmountConditionParamName, element);
SQLInjectionValidator.validateSQLInput(outstandingAmountCondition);
}
BigDecimal minOutstandingAmount = null;