sql injections fixes

This commit is contained in:
nazeer1100126
2017-05-08 18:03:47 +05:30
parent 0c658956b9
commit b7a5e67b9e
24 changed files with 611 additions and 139 deletions
@@ -242,10 +242,11 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
@Override @Override
public ProvisioningEntryData retrieveProvisioningEntryData(String date) { public ProvisioningEntryData retrieveProvisioningEntryData(String date) {
ProvisioningEntryDataMapper mapper1 = new ProvisioningEntryDataMapper(); ProvisioningEntryDataMapper mapper1 = new ProvisioningEntryDataMapper();
final String sql1 = "select " + mapper1.getSchema() + " where entry.created_date like " + "'" + date + "%'"; date = date+"%";
final String sql1 = "select " + mapper1.getSchema() + " where entry.created_date like ? ";
ProvisioningEntryData data = null; ProvisioningEntryData data = null;
try { try {
data = this.jdbcTemplate.queryForObject(sql1, mapper1, new Object[] {}); data = this.jdbcTemplate.queryForObject(sql1, mapper1, new Object[] {date});
} catch (EmptyResultDataAccessException e) { } catch (EmptyResultDataAccessException e) {
} }
@@ -41,6 +41,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper; import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.fineract.organisation.office.data.OfficeData;
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService; import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
@@ -91,6 +92,7 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
private final PaginationParametersDataValidator paginationParametersDataValidator; private final PaginationParametersDataValidator paginationParametersDataValidator;
private final SavingsProductReadPlatformService savingsProductReadPlatformService; private final SavingsProductReadPlatformService savingsProductReadPlatformService;
private final DepositProductReadPlatformService depositProductReadPlatformService; private final DepositProductReadPlatformService depositProductReadPlatformService;
private final ColumnValidator columnValidator;
@Autowired @Autowired
public AuditReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, public AuditReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
@@ -99,7 +101,8 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
final LoanProductReadPlatformService loanProductReadPlatformService, final StaffReadPlatformService staffReadPlatformService, final LoanProductReadPlatformService loanProductReadPlatformService, final StaffReadPlatformService staffReadPlatformService,
final PaginationParametersDataValidator paginationParametersDataValidator, final PaginationParametersDataValidator paginationParametersDataValidator,
final SavingsProductReadPlatformService savingsProductReadPlatformService, final SavingsProductReadPlatformService savingsProductReadPlatformService,
final DepositProductReadPlatformService depositProductReadPlatformService) { final DepositProductReadPlatformService depositProductReadPlatformService,
final ColumnValidator columnValidator) {
this.context = context; this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
this.fromApiJsonHelper = fromApiJsonHelper; this.fromApiJsonHelper = fromApiJsonHelper;
@@ -111,6 +114,7 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
this.paginationParametersDataValidator = paginationParametersDataValidator; this.paginationParametersDataValidator = paginationParametersDataValidator;
this.savingsProductReadPlatformService = savingsProductReadPlatformService; this.savingsProductReadPlatformService = savingsProductReadPlatformService;
this.depositProductReadPlatformService = depositProductReadPlatformService; this.depositProductReadPlatformService = depositProductReadPlatformService;
this.columnValidator = columnValidator;
} }
private static final class AuditMapper implements RowMapper<AuditData> { private static final class AuditMapper implements RowMapper<AuditData> {
@@ -190,7 +194,7 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
} }
updatedExtraCriteria += " order by aud.id DESC limit " + PaginationParameters.getCheckedLimit(null); updatedExtraCriteria += " order by aud.id DESC limit " + PaginationParameters.getCheckedLimit(null);
return retrieveEntries("audit", updatedExtraCriteria, includeJson); return retrieveEntries("audit", updatedExtraCriteria, includeJson, StringUtils.isNotBlank(extraCriteria));
} }
@Override @Override
@@ -203,7 +207,7 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
String updatedExtraCriteria = ""; String updatedExtraCriteria = "";
if (StringUtils.isNotBlank(extraCriteria)) { if (StringUtils.isNotBlank(extraCriteria)) {
updatedExtraCriteria = " where (" + extraCriteria + ")"; updatedExtraCriteria = " where (" + extraCriteria + ")";
} }
final AuditMapper rm = new AuditMapper(); final AuditMapper rm = new AuditMapper();
@@ -211,7 +215,7 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append(rm.schema(includeJson, hierarchy)); sqlBuilder.append(rm.schema(includeJson, hierarchy));
sqlBuilder.append(' ').append(updatedExtraCriteria); sqlBuilder.append(' ').append(updatedExtraCriteria);
this.columnValidator.validateSqlInjection(sqlBuilder.toString(), extraCriteria);
if (parameters.isOrderByRequested()) { if (parameters.isOrderByRequested()) {
sqlBuilder.append(' ').append(parameters.orderBySql()); sqlBuilder.append(' ').append(parameters.orderBySql());
} else { } else {
@@ -240,10 +244,10 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
updatedExtraCriteria += " group by aud.id order by aud.id"; updatedExtraCriteria += " group by aud.id order by aud.id";
return retrieveEntries("makerchecker", updatedExtraCriteria, includeJson); return retrieveEntries("makerchecker", updatedExtraCriteria, includeJson, StringUtils.isNotBlank(extraCriteria));
} }
public Collection<AuditData> retrieveEntries(final String useType, final String extraCriteria, final boolean includeJson) { public Collection<AuditData> retrieveEntries(final String useType, final String extraCriteria, final boolean includeJson, boolean isExtraCritereaIncluded) {
if (!(useType.equals("audit") || useType.equals("makerchecker"))) { throw new PlatformDataIntegrityException( if (!(useType.equals("audit") || useType.equals("makerchecker"))) { throw new PlatformDataIntegrityException(
"error.msg.invalid.auditSearchTemplate.useType", "Invalid Audit Search Template UseType: " + useType); } "error.msg.invalid.auditSearchTemplate.useType", "Invalid Audit Search Template UseType: " + useType); }
@@ -253,7 +257,7 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
final AuditMapper rm = new AuditMapper(); final AuditMapper rm = new AuditMapper();
String sql = "select " + rm.schema(includeJson, hierarchy); String sql = "select " + rm.schema(includeJson, hierarchy);
Boolean isLimitedChecker = false; Boolean isLimitedChecker = false;
if (useType.equals("makerchecker")) { if (useType.equals("makerchecker")) {
if (currentUser.hasNotPermissionForAnyOf("ALL_FUNCTIONS", "CHECKER_SUPER_USER")) { if (currentUser.hasNotPermissionForAnyOf("ALL_FUNCTIONS", "CHECKER_SUPER_USER")) {
@@ -267,7 +271,9 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
+ " join m_appuser_role ur on ur.role_id = r.id and ur.appuser_id = " + currentUser.getId(); + " join m_appuser_role ur on ur.role_id = r.id and ur.appuser_id = " + currentUser.getId();
} }
sql += extraCriteria; sql += extraCriteria;
if(isExtraCritereaIncluded){
this.columnValidator.validateSqlInjection(sql, extraCriteria);
}
logger.info("sql: " + sql); logger.info("sql: " + sql);
return this.jdbcTemplate.query(sql, rm, new Object[] {}); return this.jdbcTemplate.query(sql, rm, new Object[] {});
@@ -281,9 +287,9 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
final AuditMapper rm = new AuditMapper(); final AuditMapper rm = new AuditMapper();
final String sql = "select " + rm.schema(true, hierarchy) + " where aud.id = " + auditId; final String sql = "select " + rm.schema(true, hierarchy) + " where aud.id = ? ";
final AuditData auditResult = this.jdbcTemplate.queryForObject(sql, rm, new Object[] {}); final AuditData auditResult = this.jdbcTemplate.queryForObject(sql, rm, new Object[] {auditId});
return replaceIdsOnAuditData(auditResult); return replaceIdsOnAuditData(auditResult);
} }
@@ -86,17 +86,20 @@ public class EntityDatatableChecksReadPlatformServiceImpl implements EntityDatat
if (status != null || entity != null || productId != null) { if (status != null || entity != null || productId != null) {
sqlBuilder.append(" where "); sqlBuilder.append(" where ");
} }
List<Object> paramList = new ArrayList<>();
if (status != null) { if (status != null) {
sqlBuilder.append(" status_enum = " + status); sqlBuilder.append(" status_enum = ? ");
paramList.add(status);
} }
if (entity != null) { if (entity != null) {
sqlBuilder.append(" and t.application_table_name = '" + entity + "'"); sqlBuilder.append(" and t.application_table_name = ? ");
paramList.add(entity);
} }
if (productId != null) { if (productId != null) {
sqlBuilder.append(" and t.product_id = " + productId); sqlBuilder.append(" and t.product_id = ? ");
paramList.add(productId);
} }
if (searchParameters.isLimited()) { if (searchParameters.isLimited()) {
sqlBuilder.append(" limit ").append(searchParameters.getLimit()); sqlBuilder.append(" limit ").append(searchParameters.getLimit());
@@ -105,7 +108,7 @@ public class EntityDatatableChecksReadPlatformServiceImpl implements EntityDatat
} }
} }
final String sqlCountRows = "SELECT FOUND_ROWS()"; final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(jdbcTemplate, sqlCountRows, sqlBuilder.toString(), new Object[] {}, return this.paginationHelper.fetchPage(jdbcTemplate, sqlCountRows, sqlBuilder.toString(),paramList.toArray(),
entityDataTableChecksMapper); entityDataTableChecksMapper);
} }
@@ -49,6 +49,7 @@ import org.apache.fineract.infrastructure.dataqueries.exception.DatatableEntryRe
import org.apache.fineract.infrastructure.dataqueries.exception.DatatableNotFoundException; import org.apache.fineract.infrastructure.dataqueries.exception.DatatableNotFoundException;
import org.apache.fineract.infrastructure.dataqueries.exception.DatatableSystemErrorException; import org.apache.fineract.infrastructure.dataqueries.exception.DatatableSystemErrorException;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; 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.apache.fineract.useradministration.domain.AppUser;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime; import org.joda.time.LocalDateTime;
@@ -134,6 +135,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (appTable == null) { if (appTable == null) {
andClause = ""; andClause = "";
} else { } else {
SQLInjectionValidator.validateSQLInput(appTable);
andClause = " and application_table_name = '" + appTable + "'"; andClause = " and application_table_name = '" + appTable + "'";
} }
@@ -164,6 +166,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
public DatatableData retrieveDatatable(final String datatable) { public DatatableData retrieveDatatable(final String datatable) {
// PERMITTED datatables // PERMITTED datatables
SQLInjectionValidator.validateSQLInput(datatable);
final String sql = "select application_table_name, registered_table_name" + " from x_registered_table " + " where exists" final String sql = "select application_table_name, registered_table_name" + " from x_registered_table " + " where exists"
+ " (select 'f'" + " from m_appuser_role ur " + " join m_role r on r.id = ur.role_id" + " (select 'f'" + " from m_appuser_role ur " + " join m_role r on r.id = ur.role_id"
+ " left join m_role_permission rp on rp.role_id = r.id" + " left join m_permission p on p.id = rp.permission_id" + " left join m_role_permission rp on rp.role_id = r.id" + " left join m_permission p on p.id = rp.permission_id"
@@ -1161,7 +1164,9 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
// id only used for reading a specific entry in a one to many datatable // id only used for reading a specific entry in a one to many datatable
// (when updating) // (when updating)
if (id == null) { if (id == null) {
sql = sql + "select * from `" + dataTableName + "` where " + getFKField(appTable) + " = " + appTableId; String whereClause = getFKField(appTable) + " = " + appTableId;
SQLInjectionValidator.validateSQLInput(whereClause);
sql = sql + "select * from `" + dataTableName + "` where " + whereClause;
} else { } else {
sql = sql + "select * from `" + dataTableName + "` where id = " + id; sql = sql + "select * from `" + dataTableName + "` where id = " + id;
} }
@@ -1185,7 +1190,9 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
// id only used for reading a specific entry in a one to many datatable // id only used for reading a specific entry in a one to many datatable
// (when updating) // (when updating)
if (id == null) { if (id == null) {
sql = sql + "select * from `" + dataTableName + "` where " + getFKField(appTable) + " = " + appTableId; String whereClause = getFKField(appTable) + " = " + appTableId;
SQLInjectionValidator.validateSQLInput(whereClause);
sql = sql + "select * from `" + dataTableName + "` where " + whereClause;
} else { } else {
sql = sql + "select * from `" + dataTableName + "` where id = " + id; sql = sql + "select * from `" + dataTableName + "` where id = " + id;
} }
@@ -1333,6 +1340,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
} }
private String queryForApplicationTableName(final String datatable) { private String queryForApplicationTableName(final String datatable) {
SQLInjectionValidator.validateSQLInput(datatable);
final String sql = "SELECT application_table_name FROM x_registered_table where registered_table_name = '" + datatable + "'"; final String sql = "SELECT application_table_name FROM x_registered_table where registered_table_name = '" + datatable + "'";
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql); final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
@@ -0,0 +1,215 @@
/**
* Licensed to the Apache ftware Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.security.utils;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class ColumnValidator {
private final JdbcTemplate jdbcTemplate;
@Autowired
public ColumnValidator(final RoutingDataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
private void validateColumn(Map<String, Set<String>> tableColumnMap) {
try {
DatabaseMetaData dbMetaData = this.jdbcTemplate.getDataSource()
.getConnection().getMetaData();
ResultSet resultSet = null;
for (HashMap.Entry<String, Set<String>> entry : tableColumnMap
.entrySet()) {
Set<String> columns = entry.getValue();
resultSet = dbMetaData.getColumns(null, null, entry.getKey(),
null);
Set<String> tableColumns = getTableColumns(resultSet);
if (columns.size() > 0 && tableColumns.size() == 0) {
throw new SQLInjectionException();
}
for (String requestedColumn : columns) {
if (!tableColumns.contains(requestedColumn)) {
throw new SQLInjectionException();
}
}
}
} catch (SQLException e) {
throw new SQLInjectionException();
}
}
private Set<String> getTableColumns(final ResultSet rs) {
Set<String> columns = new HashSet<>();
try {
while (rs.next()) {
columns.add(rs.getString("column_name"));
}
} catch (SQLException e) {
e.printStackTrace();
}
return columns;
}
public void validateSqlInjection(String schema, String condition) {
SQLInjectionValidator.validateSQLInput(condition);
List<String> operator = new ArrayList<>(Arrays.asList("=", ">", "<",
"> =", "< =", "! =", "!=", ">=", "<="));
condition = condition.trim().replace("( ", "(").replace(" )", ")")
.toLowerCase();
for (String op : operator) {
condition = replaceAll(condition, op).replaceAll(" +", " ");
}
Set<String> operands = getOperand(condition);
schema = schema.trim().replaceAll(" +", " ").toLowerCase();
Map<String, Set<String>> tableColumnAliasMap = getTableColumnAliasMap(operands);
Map<String, Set<String>> tableColumnMap = getTableColumnMap(schema,
tableColumnAliasMap);
validateColumn(tableColumnMap);
}
private static Map<String, Set<String>> getTableColumnMap(String schema,
Map<String, Set<String>> tableColumnAliasMap) {
Map<String, Set<String>> tableColumnMap = new HashMap<>();
schema = schema.substring(schema.indexOf("from"));
for (String alias : tableColumnAliasMap.keySet()) {
int index = schema.indexOf(" " + alias + " ");
if (index > -1) {
int startPos = 0;
startPos = schema.substring(0, index - 1).lastIndexOf(' ',
index);
Set<String> columns = tableColumnAliasMap.get(alias);
tableColumnMap.put(schema.substring(startPos, index).trim(),
columns);
} else {
throw new SQLInjectionException();
}
}
return tableColumnMap;
}
private static Map<String, Set<String>> getTableColumnAliasMap(
Set<String> operands) {
Map<String, Set<String>> tableColumnMap = new HashMap<>();
for (String operand : operands) {
String[] tableColumn = operand.split("\\.");
if (tableColumn.length == 2) {
if (tableColumnMap.containsKey(tableColumn[0])) {
Set<String> columns = tableColumnMap.get(tableColumn[0]);
columns.add(tableColumn[1]);
} else {
Set<String> columns = new HashSet<>();
columns.add(tableColumn[1]);
tableColumnMap.put(tableColumn[0], columns);
}
} else {
throw new SQLInjectionException();
}
}
return tableColumnMap;
}
private static Set<String> getOperand(String condition) {
Set<String> operandList = new HashSet<>();
List<String> operatorList = new ArrayList<>(Arrays.asList("!=", "=",
">", "<", " like ", " between ", " in ", " in(", " is ",
" is not ", " equals ", " not equals "));
for (String op : operatorList) {
int startIndex = 0;
do {
int index = condition.indexOf(op, startIndex);
if (index > -1) {
char currentChar = condition.charAt(index - 1);
if (op.equals("=")) {
if (!((currentChar + "").equals("!")
|| (currentChar + "").equals(">") || (currentChar + "")
.equals("<"))) {
operandList.add(getOperand(condition, index,
currentChar));
}
} else {
operandList.add(getOperand(condition, index,
currentChar));
}
startIndex = index + op.length();
}
} while (condition.indexOf(op, startIndex) > -1);
}
return operandList;
}
private static String getOperand(String condition, int index,
char currentChar) {
int startPos = 0;
if ((currentChar + "").equals(" ")) {
startPos = condition.substring(0, index - 1)
.lastIndexOf(' ', index);
} else {
startPos = condition.substring(0, index).lastIndexOf(' ', index);
}
String a = condition.substring(startPos == -1 ? 0 : startPos, index);
return a.trim().replace("(", "").replace(")", "");
}
private static String replaceAll(String condition, String op) {
int startIndex = 0;
do {
int index = condition.indexOf(op, startIndex);
if (index > -1) {
if (op.equals("=")) {
if (!((condition.charAt(index - 1) + "").equals("!")
|| (condition.charAt(index - 1) + "").equals(">") || (condition
.charAt(index - 1) + "").equals("<"))) {
condition = condition.replace(op, " " + op + " ");
return condition;
}
startIndex = index + 2 + op.length();
} else if (op.equals("< =") || op.equals("> =")
|| op.equals("! =")) {
condition = condition.replace(op, op.replace(" ", ""));
return condition;
} else {
condition = condition.replace(op, " " + op + " ");
return condition;
}
} else {
return condition;
}
} while (condition.indexOf(op, startIndex) > -1);
return condition;
}
}
@@ -0,0 +1,29 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.security.utils;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
public class SQLInjectionException extends PlatformApiDataValidationException {
public SQLInjectionException() {
super("error.msg.found.sql.injection", "Unexpected SQL Commands found", null);
}
}
@@ -0,0 +1,117 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.security.utils;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SQLInjectionValidator {
private final static String[] DDL_COMMANDS = { "create", "drop", "alter", "truncate", "comment" };
private final static String[] DML_COMMANDS = { "select", "insert", "update", "delete", "merge", "upsert", "call" };
private final static String[] COMMENTS = { "--", "({", "/*", "#" };
private final static String SQL_PATTERN = "[a-zA-Z_=,'!><.?\"`% ()0-9]*";
public final static void validateSQLInput(final String sqlSearch) {
String lowerCaseSQL = sqlSearch.toLowerCase();
for (String ddl : DDL_COMMANDS) {
if (lowerCaseSQL.contains(ddl)) {
throw new SQLInjectionException();
}
}
for (String dml : DML_COMMANDS) {
if (lowerCaseSQL.contains(dml)) {
throw new SQLInjectionException();
}
}
for (String comments : COMMENTS) {
if (lowerCaseSQL.contains(comments)) {
throw new SQLInjectionException();
}
}
//Removing the space before and after '=' operator
//String s = " \" OR 1 = 1"; For the cases like this
boolean injectionFound = false;
String inputSqlString = lowerCaseSQL;
while (inputSqlString.indexOf(" =") > 0) { //Don't remove space before = operator
inputSqlString = inputSqlString.replaceAll(" =", "=");
}
while (inputSqlString.indexOf("= ") > 0) { //Don't remove space after = operator
inputSqlString = inputSqlString.replaceAll("= ", "=");
}
StringTokenizer tokenizer = new StringTokenizer(inputSqlString, " ");
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken().trim();
if (token.equals("'")) {
if (tokenizer.hasMoreElements()) {
String nextToken = tokenizer.nextToken().trim();
if (!nextToken.equals("'")) {
injectionFound = true;
break;
}
} else {
injectionFound = true;
break ;
}
}
if (token.equals("\"")) {
if (tokenizer.hasMoreElements()) {
String nextToken = tokenizer.nextToken().trim();
if (!nextToken.equals("\"")) {
injectionFound = true;
break;
}
} else {
injectionFound = true;
break ;
}
} else if (token.indexOf('=') > 0) {
StringTokenizer operatorToken = new StringTokenizer(token, "=");
String operand = operatorToken.nextToken().trim();
if (!operatorToken.hasMoreTokens()) {
injectionFound = true;
break;
}
String value = operatorToken.nextToken().trim();
if (operand.equals(value)) {
injectionFound = true;
break;
}
}
}
if (injectionFound) {
throw new SQLInjectionException();
}
Pattern pattern = Pattern.compile(SQL_PATTERN);
Matcher matcher = pattern.matcher(sqlSearch);
if (!matcher.matches()) {
throw new SQLInjectionException();
}
}
}
@@ -31,6 +31,7 @@ import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeader
import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService; import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService;
import org.apache.fineract.infrastructure.dataqueries.service.ReadWriteNonCoreDataService; import org.apache.fineract.infrastructure.dataqueries.service.ReadWriteNonCoreDataService;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
import org.apache.fineract.infrastructure.survey.data.ClientScoresOverview; import org.apache.fineract.infrastructure.survey.data.ClientScoresOverview;
import org.apache.fineract.infrastructure.survey.data.LikelihoodStatus; import org.apache.fineract.infrastructure.survey.data.LikelihoodStatus;
import org.apache.fineract.infrastructure.survey.data.SurveyDataTableData; import org.apache.fineract.infrastructure.survey.data.SurveyDataTableData;
@@ -96,6 +97,7 @@ public class ReadSurveyServiceImpl implements ReadSurveyService {
@Override @Override
public SurveyDataTableData retrieveSurvey(String surveyName) { public SurveyDataTableData retrieveSurvey(String surveyName) {
SQLInjectionValidator.validateSQLInput(surveyName);
final String sql = "select cf.enabled, application_table_name, registered_table_name" + " from x_registered_table " final String sql = "select cf.enabled, application_table_name, registered_table_name" + " from x_registered_table "
+ " left join c_configuration cf on x_registered_table.registered_table_name = cf.name " + " where exists" + " (select 'f'" + " left join c_configuration cf on x_registered_table.registered_table_name = cf.name " + " where exists" + " (select 'f'"
+ " from m_appuser_role ur " + " join m_role r on r.id = ur.role_id" + " from m_appuser_role ur " + " join m_role r on r.id = ur.role_id"
@@ -125,13 +127,13 @@ public class ReadSurveyServiceImpl implements ReadSurveyService {
@Override @Override
public List<ClientScoresOverview> retrieveClientSurveyScoreOverview(String surveyName, Long clientId) { public List<ClientScoresOverview> retrieveClientSurveyScoreOverview(String surveyName, Long clientId) {
final String sql = "SELECT tz.id, lkh.name, lkh.code, poverty_line, tz.date, tz.score FROM " + surveyName + " tz" final String sql = "SELECT tz.id, lkh.name, lkh.code, poverty_line, tz.date, tz.score FROM ? tz"
+ " JOIN ppi_likelihoods_ppi lkp on lkp.ppi_name = '" + surveyName + "' AND enabled = '" + LikelihoodStatus.ENABLED + " JOIN ppi_likelihoods_ppi lkp on lkp.ppi_name = ? AND enabled = ? "
+ "' JOIN ppi_scores sc on score_from <= tz.score AND score_to >=tz.score" + " JOIN ppi_scores sc on score_from <= tz.score AND score_to >=tz.score"
+ " JOIN ppi_poverty_line pvl on pvl.likelihood_ppi_id = lkp.id AND pvl.score_id = sc.id" + " JOIN ppi_poverty_line pvl on pvl.likelihood_ppi_id = lkp.id AND pvl.score_id = sc.id"
+ " JOIN ppi_likelihoods lkh on lkh.id = lkp.likelihood_id " + " WHERE client_id = " + clientId; + " JOIN ppi_likelihoods lkh on lkh.id = lkp.likelihood_id " + " WHERE client_id = ? ";
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql); final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql, new Object[] { surveyName, surveyName, LikelihoodStatus.ENABLED, clientId });
List<ClientScoresOverview> scoresOverviews = new ArrayList<>(); List<ClientScoresOverview> scoresOverviews = new ArrayList<>();
@@ -70,7 +70,7 @@ public class MixTaxonomyReadPlatformServiceImpl implements MixTaxonomyReadPlatfo
@Override @Override
public MixTaxonomyData retrieveOne(final Long id) { public MixTaxonomyData retrieveOne(final Long id) {
final String sql = "select " + this.mixTaxonomyMapper.schema() + " where tx.id =" + id; final String sql = "select " + this.mixTaxonomyMapper.schema() + " where tx.id = ? ";
return this.jdbcTemplate.queryForObject(sql, this.mixTaxonomyMapper); return this.jdbcTemplate.queryForObject(sql, this.mixTaxonomyMapper, new Object[] { id });
} }
} }
@@ -58,15 +58,15 @@ public class NamespaceReadPlatformServiceImpl implements NamespaceReadPlatformSe
@Override @Override
public NamespaceData retrieveNamespaceById(final Long id) { public NamespaceData retrieveNamespaceById(final Long id) {
final String sql = this.namespaceMapper.schema() + " where id=" + id; final String sql = this.namespaceMapper.schema() + " where id= ? ";
return this.jdbcTemplate.queryForObject(sql, this.namespaceMapper); return this.jdbcTemplate.queryForObject(sql, this.namespaceMapper, new Object[] { id });
} }
@Override @Override
public NamespaceData retrieveNamespaceByPrefix(final String prefix) { public NamespaceData retrieveNamespaceByPrefix(final String prefix) {
final String sql = this.namespaceMapper.schema() + " where prefix='" + prefix + "'"; final String sql = this.namespaceMapper.schema() + " where prefix = ? ";
return this.jdbcTemplate.queryForObject(sql, this.namespaceMapper); return this.jdbcTemplate.queryForObject(sql, this.namespaceMapper, new Object[] { prefix });
} }
} }
@@ -30,6 +30,8 @@ import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.organisation.staff.exception.StaffNotFoundException; import org.apache.fineract.organisation.staff.exception.StaffNotFoundException;
import org.apache.fineract.portfolio.client.domain.ClientStatus; import org.apache.fineract.portfolio.client.domain.ClientStatus;
@@ -49,11 +51,14 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final StaffLookupMapper lookupMapper = new StaffLookupMapper(); private final StaffLookupMapper lookupMapper = new StaffLookupMapper();
private final StaffInOfficeHierarchyMapper staffInOfficeHierarchyMapper = new StaffInOfficeHierarchyMapper(); private final StaffInOfficeHierarchyMapper staffInOfficeHierarchyMapper = new StaffInOfficeHierarchyMapper();
private final ColumnValidator columnValidator;
@Autowired @Autowired
public StaffReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource) { public StaffReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
final ColumnValidator columnValidator) {
this.context = context; this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
this.columnValidator = columnValidator;
} }
private static final class StaffMapper implements RowMapper<StaffData> { private static final class StaffMapper implements RowMapper<StaffData> {
@@ -157,20 +162,20 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
@Override @Override
public Collection<StaffData> retrieveAllLoanOfficersInOfficeById(final Long officeId) { public Collection<StaffData> retrieveAllLoanOfficersInOfficeById(final Long officeId) {
return retrieveAllStaff(" office_id=" + officeId + " and is_loan_officer=1"); return retrieveAllStaff(" office_id = ? and is_loan_officer=1", officeId);
} }
@Override @Override
public Collection<StaffData> retrieveAllStaffForDropdown(final Long officeId) { public Collection<StaffData> retrieveAllStaffForDropdown(final Long officeId) {
//adding the Authorization criteria so that a user cannot see an employee who does not belong to his office or a sub office for his office. //adding the Authorization criteria so that a user cannot see an employee who does not belong to his office or a sub office for his office.
final String hierarchy = this.context.authenticatedUser().getOffice().getHierarchy(); final String hierarchy = this.context.authenticatedUser().getOffice().getHierarchy()+"%";
final Long defaultOfficeId = defaultToUsersOfficeIfNull(officeId); final Long defaultOfficeId = defaultToUsersOfficeIfNull(officeId);
final String sql = "select " + this.lookupMapper.schema() + " where s.office_id = ? and s.is_active=1 and o.hierarchy like '"+ hierarchy+ "%'"; final String sql = "select " + this.lookupMapper.schema() + " where s.office_id = ? and s.is_active=1 and o.hierarchy like ? ";
return this.jdbcTemplate.query(sql, this.lookupMapper, new Object[] { defaultOfficeId }); return this.jdbcTemplate.query(sql, this.lookupMapper, new Object[] { defaultOfficeId, hierarchy });
} }
private Long defaultToUsersOfficeIfNull(final Long officeId) { private Long defaultToUsersOfficeIfNull(final Long officeId) {
@@ -185,14 +190,14 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
public StaffData retrieveStaff(final Long staffId) { public StaffData retrieveStaff(final Long staffId) {
//adding the Authorization criteria so that a user cannot see an employee who does not belong to his office or a sub office for his office. //adding the Authorization criteria so that a user cannot see an employee who does not belong to his office or a sub office for his office.
final String hierarchy = this.context.authenticatedUser().getOffice().getHierarchy(); final String hierarchy = this.context.authenticatedUser().getOffice().getHierarchy()+ "%";
try { try {
final StaffMapper rm = new StaffMapper(); final StaffMapper rm = new StaffMapper();
final String sql = "select " + rm.schema() + " where s.id = ? and o.hierarchy like '"+ hierarchy+ "%'" ; final String sql = "select " + rm.schema() + " where s.id = ? and o.hierarchy like ? " ;
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { staffId }); return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { staffId, hierarchy });
} catch (final EmptyResultDataAccessException e) { } catch (final EmptyResultDataAccessException e) {
throw new StaffNotFoundException(staffId); throw new StaffNotFoundException(staffId);
} }
@@ -202,18 +207,22 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
public Collection<StaffData> retrieveAllStaff(final String sqlSearch, final Long officeId, final boolean loanOfficersOnly, public Collection<StaffData> retrieveAllStaff(final String sqlSearch, final Long officeId, final boolean loanOfficersOnly,
final String status) { final String status) {
final String extraCriteria = getStaffCriteria(sqlSearch, officeId, loanOfficersOnly, status); final String extraCriteria = getStaffCriteria(sqlSearch, officeId, loanOfficersOnly, status);
return retrieveAllStaff(extraCriteria); return retrieveAllStaff(extraCriteria, officeId);
} }
private Collection<StaffData> retrieveAllStaff(final String extraCriteria) { private Collection<StaffData> retrieveAllStaff(final String extraCriteria, Long officeId) {
final StaffMapper rm = new StaffMapper(); final StaffMapper rm = new StaffMapper();
String sql = "select " + rm.schema(); String sql = "select " + rm.schema();
if (StringUtils.isNotBlank(extraCriteria)) { final String hierarchy = this.context.authenticatedUser().getOffice().getHierarchy()+"%";
sql += " where " + extraCriteria; if (StringUtils.isNotBlank(extraCriteria)){
sql += " where " + extraCriteria;
} }
sql = sql + " order by s.lastname"; sql = sql + " order by s.lastname";
return this.jdbcTemplate.query(sql, rm, new Object[] {}); if(officeId==null){
return this.jdbcTemplate.query(sql, rm, new Object[] {hierarchy });
}
return this.jdbcTemplate.query(sql, rm, new Object[] {officeId, hierarchy });
} }
private String getStaffCriteria(final String sqlSearch, final Long officeId, final boolean loanOfficersOnly, final String status) { private String getStaffCriteria(final String sqlSearch, final Long officeId, final boolean loanOfficersOnly, final String status) {
@@ -222,9 +231,11 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
if (sqlSearch != null) { if (sqlSearch != null) {
extraCriteria.append(" and (").append(sqlSearch).append(")"); extraCriteria.append(" and (").append(sqlSearch).append(")");
final StaffMapper rm = new StaffMapper();
this.columnValidator.validateSqlInjection(rm.schema(), sqlSearch);
} }
if (officeId != null) { if (officeId != null) {
extraCriteria.append(" and office_id = ").append(officeId).append(" "); extraCriteria.append(" and s.office_id = ? ");
} }
if (loanOfficersOnly) { if (loanOfficersOnly) {
extraCriteria.append(" and s.is_loan_officer is true "); extraCriteria.append(" and s.is_loan_officer is true ");
@@ -232,21 +243,21 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
// Passing status parameter to get ACTIVE (By Default), INACTIVE or ALL // Passing status parameter to get ACTIVE (By Default), INACTIVE or ALL
// (Both active and Inactive) employees // (Both active and Inactive) employees
if (status.equalsIgnoreCase("active")) { if (status.equalsIgnoreCase("active")) {
extraCriteria.append(" and is_active = 1 "); extraCriteria.append(" and s.is_active = 1 ");
} else if (status.equalsIgnoreCase("inActive")) { } else if (status.equalsIgnoreCase("inActive")) {
extraCriteria.append(" and is_active = 0 "); extraCriteria.append(" and s.is_active = 0 ");
} else if (status.equalsIgnoreCase("all")) {} else { } else if (status.equalsIgnoreCase("all")) {} else {
throw new UnrecognizedQueryParamException("status", status, new Object[] { "all", "active", "inactive" }); throw new UnrecognizedQueryParamException("status", status, new Object[] { "all", "active", "inactive" });
} }
//adding the Authorization criteria so that a user cannot see an employee who does not belong to his office or a sub office for his office. //adding the Authorization criteria so that a user cannot see an employee who does not belong to his office or a sub office for his office.
final String hierarchy = this.context.authenticatedUser().getOffice().getHierarchy();
extraCriteria.append(" and o.hierarchy like '"+ hierarchy+ "%' "); extraCriteria.append(" and o.hierarchy like ? ");
if (StringUtils.isNotBlank(extraCriteria.toString())) { if (StringUtils.isNotBlank(extraCriteria.toString())) {
extraCriteria.delete(0, 4); extraCriteria.delete(0, 4);
} }
// remove begin four letter including a space from the string. // remove begin four letter including a space from the string.
return extraCriteria.toString(); return extraCriteria.toString();
} }
@@ -265,15 +276,21 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
String sql = "select c.display_name as client, g.display_name as grp,l.loan_officer_id as loan, s.field_officer_id as sav"+ String sql = "select c.display_name as client, g.display_name as grp,l.loan_officer_id as loan, s.field_officer_id as sav"+
" from m_staff staff "+ " from m_staff staff "+
" left outer join m_client c on staff.id = c.staff_id AND c.status_enum < "+ ClientStatus.CLOSED.getValue() + " left outer join m_client c on staff.id = c.staff_id AND c.status_enum < ? "+
" left outer join m_group g on staff.id = g.staff_id " + " left outer join m_group g on staff.id = g.staff_id " +
" left outer join m_loan l on staff.id = l.loan_officer_id and l.loan_status_id < " + LoanStatus.WITHDRAWN_BY_CLIENT.getValue() + " left outer join m_loan l on staff.id = l.loan_officer_id and l.loan_status_id < ? " +
" left outer join m_savings_account s on c.staff_id = s.field_officer_id and s.status_enum < "+ SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT.getValue() + " left outer join m_savings_account s on c.staff_id = s.field_officer_id and s.status_enum < ? "+
" where staff.id = " + staffId + " where staff.id = ? "+
" group by staff.id"; " group by staff.id";
List<Map<String, Object>> result = this.jdbcTemplate.queryForList(sql); List<Map<String, Object>> result = this.jdbcTemplate.queryForList(
sql,
new Object[] {
ClientStatus.CLOSED.getValue(),
LoanStatus.WITHDRAWN_BY_CLIENT.getValue(),
SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT
.getValue(), staffId });
if (result != null) { if (result != null) {
for (Map<String, Object> map : result) { for (Map<String, Object> map : result) {
if (map.get("client") != null) { if (map.get("client") != null) {
@@ -33,6 +33,7 @@ import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters; import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService; import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService;
import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.fineract.organisation.office.data.OfficeData;
@@ -70,16 +71,18 @@ public class TellerManagementReadPlatformServiceImpl implements TellerManagement
private final StaffReadPlatformService staffReadPlatformService; private final StaffReadPlatformService staffReadPlatformService;
private final CurrencyReadPlatformService currencyReadPlatformService; private final CurrencyReadPlatformService currencyReadPlatformService;
private final PaginationHelper<CashierTransactionData> paginationHelper = new PaginationHelper<>(); private final PaginationHelper<CashierTransactionData> paginationHelper = new PaginationHelper<>();
private final ColumnValidator columnValidator;
@Autowired @Autowired
public TellerManagementReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, public TellerManagementReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
final OfficeReadPlatformService officeReadPlatformService, StaffReadPlatformService staffReadPlatformService, final OfficeReadPlatformService officeReadPlatformService, StaffReadPlatformService staffReadPlatformService,
final CurrencyReadPlatformService currencyReadPlatformService) { final CurrencyReadPlatformService currencyReadPlatformService, final ColumnValidator columnValidator) {
this.context = context; this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
this.officeReadPlatformService = officeReadPlatformService; this.officeReadPlatformService = officeReadPlatformService;
this.staffReadPlatformService = staffReadPlatformService; this.staffReadPlatformService = staffReadPlatformService;
this.currencyReadPlatformService = currencyReadPlatformService; this.currencyReadPlatformService = currencyReadPlatformService;
this.columnValidator = columnValidator;
} }
private static final class TellerMapper implements RowMapper<TellerData> { private static final class TellerMapper implements RowMapper<TellerData> {
@@ -223,11 +226,11 @@ public class TellerManagementReadPlatformServiceImpl implements TellerManagement
@Override @Override
public Collection<TellerData> retrieveAllTellers(final String sqlSearch, final Long officeId, final String status) { public Collection<TellerData> retrieveAllTellers(final String sqlSearch, final Long officeId, final String status) {
final String extraCriteria = getTellerCriteria(sqlSearch, officeId, status); final String extraCriteria = getTellerCriteria(sqlSearch, officeId, status);
return retrieveAllTeller(extraCriteria); return retrieveAllTeller(extraCriteria, officeId);
} }
private Collection<TellerData> retrieveAllTeller(final String extraCriteria) { private Collection<TellerData> retrieveAllTeller(final String extraCriteria, final Long officeId) {
final TellerMapper tm = new TellerMapper(); final TellerMapper tm = new TellerMapper();
String sql = "select " + tm.schema(); String sql = "select " + tm.schema();
@@ -235,6 +238,9 @@ public class TellerManagementReadPlatformServiceImpl implements TellerManagement
sql += " where " + extraCriteria; sql += " where " + extraCriteria;
} }
sql = sql + " order by t.teller_name"; sql = sql + " order by t.teller_name";
if(officeId!=null){
return this.jdbcTemplate.query(sql, tm, new Object[] {officeId});
}
return this.jdbcTemplate.query(sql, tm, new Object[] {}); return this.jdbcTemplate.query(sql, tm, new Object[] {});
} }
@@ -244,9 +250,11 @@ public class TellerManagementReadPlatformServiceImpl implements TellerManagement
if (sqlSearch != null) { if (sqlSearch != null) {
extraCriteria.append(" and (").append(sqlSearch).append(")"); extraCriteria.append(" and (").append(sqlSearch).append(")");
final TellerMapper tm = new TellerMapper();
this.columnValidator.validateSqlInjection(tm.schema(), sqlSearch);
} }
if (officeId != null) { if (officeId != null) {
extraCriteria.append(" and office_id = ").append(officeId).append(" "); extraCriteria.append(" and office_id = ? ");
} }
// Passing status parameter to get ACTIVE (By Default), INACTIVE or ALL // Passing status parameter to get ACTIVE (By Default), INACTIVE or ALL
// (Both active and Inactive) employees // (Both active and Inactive) employees
@@ -278,7 +286,7 @@ public class TellerManagementReadPlatformServiceImpl implements TellerManagement
@Override @Override
public Collection<CashierData> retrieveCashiersForTellers(final String sqlSearch, final Long tellerId) { public Collection<CashierData> retrieveCashiersForTellers(final String sqlSearch, final Long tellerId) {
final String extraCriteria = getTellerCriteria(sqlSearch, tellerId); final String extraCriteria = getTellerCriteria(sqlSearch, tellerId);
return fetchCashiers(extraCriteria); return fetchCashiers(extraCriteria);
} }
@@ -288,6 +296,9 @@ public class TellerManagementReadPlatformServiceImpl implements TellerManagement
if (sqlSearch != null) { if (sqlSearch != null) {
extraCriteria.append(" and (").append(sqlSearch).append(")"); extraCriteria.append(" and (").append(sqlSearch).append(")");
final CashierMapper cm = new CashierMapper();
this.columnValidator.validateSqlInjection(cm.schema(), sqlSearch);
} }
if (tellerId != null) { if (tellerId != null) {
extraCriteria.append(" and teller_id = ").append(tellerId).append(" "); extraCriteria.append(" and teller_id = ").append(tellerId).append(" ");
@@ -27,6 +27,7 @@ import java.util.List;
import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport; import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData; import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData;
import org.apache.fineract.portfolio.accountdetails.data.LoanAccountSummaryData; import org.apache.fineract.portfolio.accountdetails.data.LoanAccountSummaryData;
@@ -56,13 +57,16 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
private final JdbcTemplate jdbcTemplate; private final JdbcTemplate jdbcTemplate;
private final ClientReadPlatformService clientReadPlatformService; private final ClientReadPlatformService clientReadPlatformService;
private final GroupReadPlatformService groupReadPlatformService; private final GroupReadPlatformService groupReadPlatformService;
private final ColumnValidator columnValidator;
@Autowired @Autowired
public AccountDetailsReadPlatformServiceJpaRepositoryImpl(final ClientReadPlatformService clientReadPlatformService, public AccountDetailsReadPlatformServiceJpaRepositoryImpl(final ClientReadPlatformService clientReadPlatformService,
final RoutingDataSource dataSource, final GroupReadPlatformService groupReadPlatformService) { final RoutingDataSource dataSource, final GroupReadPlatformService groupReadPlatformService,
final ColumnValidator columnValidator) {
this.clientReadPlatformService = clientReadPlatformService; this.clientReadPlatformService = clientReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
this.groupReadPlatformService = groupReadPlatformService; this.groupReadPlatformService = groupReadPlatformService;
this.columnValidator = columnValidator;
} }
@Override @Override
@@ -119,6 +123,7 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
private List<LoanAccountSummaryData> retrieveLoanAccountDetails(final String loanwhereClause, final Object[] inputs) { private List<LoanAccountSummaryData> retrieveLoanAccountDetails(final String loanwhereClause, final Object[] inputs) {
final LoanAccountSummaryDataMapper rm = new LoanAccountSummaryDataMapper(); final LoanAccountSummaryDataMapper rm = new LoanAccountSummaryDataMapper();
final String sql = "select " + rm.loanAccountSummarySchema() + loanwhereClause; final String sql = "select " + rm.loanAccountSummarySchema() + loanwhereClause;
this.columnValidator.validateSqlInjection(rm.loanAccountSummarySchema(), loanwhereClause);
return this.jdbcTemplate.query(sql, rm, inputs); return this.jdbcTemplate.query(sql, rm, inputs);
} }
@@ -129,6 +134,7 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
private List<SavingsAccountSummaryData> retrieveAccountDetails(final String savingswhereClause, final Object[] inputs) { private List<SavingsAccountSummaryData> retrieveAccountDetails(final String savingswhereClause, final Object[] inputs) {
final SavingsAccountSummaryDataMapper savingsAccountSummaryDataMapper = new SavingsAccountSummaryDataMapper(); final SavingsAccountSummaryDataMapper savingsAccountSummaryDataMapper = new SavingsAccountSummaryDataMapper();
final String savingsSql = "select " + savingsAccountSummaryDataMapper.schema() + savingswhereClause; final String savingsSql = "select " + savingsAccountSummaryDataMapper.schema() + savingswhereClause;
this.columnValidator.validateSqlInjection(savingsAccountSummaryDataMapper.schema() , savingswhereClause);
return this.jdbcTemplate.query(savingsSql, savingsAccountSummaryDataMapper, inputs); return this.jdbcTemplate.query(savingsSql, savingsAccountSummaryDataMapper, inputs);
} }
@@ -102,13 +102,13 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
public Collection<ChargeData> retrieveAllChargesForCurrency(String currencyCode) { public Collection<ChargeData> retrieveAllChargesForCurrency(String currencyCode) {
final ChargeMapper rm = new ChargeMapper(); final ChargeMapper rm = new ChargeMapper();
String sql = "select " + rm.chargeSchema() + " where c.is_deleted=false and c.currency_code='" + currencyCode + "' "; String sql = "select " + rm.chargeSchema() + " where c.is_deleted=false and c.currency_code= ? ";
sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled();
sql += " order by c.name "; sql += " order by c.name ";
return this.jdbcTemplate.query(sql, rm, new Object[] {}); return this.jdbcTemplate.query(sql, rm, new Object[] {currencyCode});
} }
@Override @Override
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.client.service;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@@ -41,6 +42,7 @@ import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.fineract.organisation.office.data.OfficeData;
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService; import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
@@ -86,6 +88,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
private final AddressReadPlatformService addressReadPlatformService; private final AddressReadPlatformService addressReadPlatformService;
private final ConfigurationReadPlatformService configurationReadPlatformService; private final ConfigurationReadPlatformService configurationReadPlatformService;
private final EntityDatatableChecksReadService entityDatatableChecksReadService; private final EntityDatatableChecksReadService entityDatatableChecksReadService;
private final ColumnValidator columnValidator;
@Autowired @Autowired
public ClientReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, public ClientReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
@@ -94,7 +97,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final SavingsProductReadPlatformService savingsProductReadPlatformService, final SavingsProductReadPlatformService savingsProductReadPlatformService,
final AddressReadPlatformService addressReadPlatformService, final AddressReadPlatformService addressReadPlatformService,
final ConfigurationReadPlatformService configurationReadPlatformService, final ConfigurationReadPlatformService configurationReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService) { final EntityDatatableChecksReadService entityDatatableChecksReadService,
final ColumnValidator columnValidator) {
this.context = context; this.context = context;
this.officeReadPlatformService = officeReadPlatformService; this.officeReadPlatformService = officeReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
@@ -104,6 +108,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
this.addressReadPlatformService=addressReadPlatformService; this.addressReadPlatformService=addressReadPlatformService;
this.configurationReadPlatformService=configurationReadPlatformService; this.configurationReadPlatformService=configurationReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService; this.entityDatatableChecksReadService = entityDatatableChecksReadService;
this.columnValidator = columnValidator;
} }
@Override @Override
@@ -165,6 +170,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
} }
@Override @Override
// @Transactional(readOnly=true)
public Page<ClientData> retrieveAll(final SearchParameters searchParameters) { public Page<ClientData> retrieveAll(final SearchParameters searchParameters) {
final String userOfficeHierarchy = this.context.officeHierarchy(); final String userOfficeHierarchy = this.context.officeHierarchy();
@@ -175,7 +181,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
// this.context.validateAccessRights(searchParameters.getHierarchy()); // this.context.validateAccessRights(searchParameters.getHierarchy());
// underHierarchySearchString = searchParameters.getHierarchy() + "%"; // underHierarchySearchString = searchParameters.getHierarchy() + "%";
// } // }
List<Object> paramList = new ArrayList<>(Arrays.asList(underHierarchySearchString, underHierarchySearchString));
final StringBuilder sqlBuilder = new StringBuilder(200); final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append(this.clientMapper.schema()); sqlBuilder.append(this.clientMapper.schema());
@@ -183,10 +189,11 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
if(searchParameters.isSelfUser()){ if(searchParameters.isSelfUser()){
sqlBuilder.append(" and c.id in (select umap.client_id from m_selfservice_user_client_mapping as umap where umap.appuser_id = ? ) "); sqlBuilder.append(" and c.id in (select umap.client_id from m_selfservice_user_client_mapping as umap where umap.appuser_id = ? ) ");
paramList.add(appUserID);
} }
final String extraCriteria = buildSqlStringFromClientCriteria(searchParameters); final String extraCriteria = buildSqlStringFromClientCriteria(this.clientMapper.schema(), searchParameters, paramList);
if (StringUtils.isNotBlank(extraCriteria)) { if (StringUtils.isNotBlank(extraCriteria)) {
sqlBuilder.append(" and (").append(extraCriteria).append(")"); sqlBuilder.append(" and (").append(extraCriteria).append(")");
} }
@@ -207,14 +214,10 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
} }
final String sqlCountRows = "SELECT FOUND_ROWS()"; final String sqlCountRows = "SELECT FOUND_ROWS()";
Object[] params = new Object[] {underHierarchySearchString, underHierarchySearchString }; return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), paramList.toArray(), this.clientMapper);
if(searchParameters.isSelfUser()){
params = new Object[] {underHierarchySearchString, underHierarchySearchString, appUserID };
}
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), params, this.clientMapper);
} }
private String buildSqlStringFromClientCriteria(final SearchParameters searchParameters) { private String buildSqlStringFromClientCriteria(String schemaSql, final SearchParameters searchParameters, List<Object> paramList) {
String sqlSearch = searchParameters.getSqlSearch(); String sqlSearch = searchParameters.getSqlSearch();
final Long officeId = searchParameters.getOfficeId(); final Long officeId = searchParameters.getOfficeId();
@@ -228,32 +231,38 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
sqlSearch = sqlSearch.replaceAll(" display_name ", " c.display_name "); sqlSearch = sqlSearch.replaceAll(" display_name ", " c.display_name ");
sqlSearch = sqlSearch.replaceAll("display_name ", "c.display_name "); sqlSearch = sqlSearch.replaceAll("display_name ", "c.display_name ");
extraCriteria = " and (" + sqlSearch + ")"; extraCriteria = " and (" + sqlSearch + ")";
this.columnValidator.validateSqlInjection(schemaSql, sqlSearch);
} }
if (officeId != null) { if (officeId != null) {
extraCriteria += " and c.office_id = " + officeId; extraCriteria += " and c.office_id = ? ";
paramList.add(officeId);
} }
if (externalId != null) { if (externalId != null) {
extraCriteria += " and c.external_id like " + ApiParameterHelper.sqlEncodeString(externalId); paramList.add(ApiParameterHelper.sqlEncodeString(externalId));
extraCriteria += " and c.external_id like ? " ;
} }
if (displayName != null) { if (displayName != null) {
//extraCriteria += " and concat(ifnull(c.firstname, ''), if(c.firstname > '',' ', '') , ifnull(c.lastname, '')) like " //extraCriteria += " and concat(ifnull(c.firstname, ''), if(c.firstname > '',' ', '') , ifnull(c.lastname, '')) like "
extraCriteria += " and c.display_name like " paramList.add(ApiParameterHelper.sqlEncodeString(ApiParameterHelper.sqlEncodeString("%" + displayName + "%")));
+ ApiParameterHelper.sqlEncodeString("%" + displayName + "%"); extraCriteria += " and c.display_name like ? ";
} }
if (firstname != null) { if (firstname != null) {
extraCriteria += " and c.firstname like " + ApiParameterHelper.sqlEncodeString(firstname); paramList.add(ApiParameterHelper.sqlEncodeString(firstname));
extraCriteria += " and c.firstname like ? " ;
} }
if (lastname != null) { if (lastname != null) {
extraCriteria += " and c.lastname like " + ApiParameterHelper.sqlEncodeString(lastname); paramList.add(ApiParameterHelper.sqlEncodeString(lastname));
extraCriteria += " and c.lastname like ? ";
} }
if (searchParameters.isScopedByOfficeHierarchy()) { if (searchParameters.isScopedByOfficeHierarchy()) {
extraCriteria += " and o.hierarchy like " + ApiParameterHelper.sqlEncodeString(searchParameters.getHierarchy() + "%"); paramList.add(ApiParameterHelper.sqlEncodeString(searchParameters.getHierarchy() + "%"));
extraCriteria += " and o.hierarchy like ? ";
} }
if(searchParameters.isOrphansOnly()){ if(searchParameters.isOrphansOnly()){
@@ -263,7 +272,6 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
if (StringUtils.isNotBlank(extraCriteria)) { if (StringUtils.isNotBlank(extraCriteria)) {
extraCriteria = extraCriteria.substring(4); extraCriteria = extraCriteria.substring(4);
} }
return extraCriteria; return extraCriteria;
} }
@@ -297,8 +305,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
if (StringUtils.isNotBlank(extraCriteria)) { if (StringUtils.isNotBlank(extraCriteria)) {
sql += " and (" + extraCriteria + ")"; sql += " and (" + extraCriteria + ")";
} this.columnValidator.validateSqlInjection(sql, extraCriteria);
}
return this.jdbcTemplate.query(sql, this.lookupMapper, new Object[] {}); return this.jdbcTemplate.query(sql, this.lookupMapper, new Object[] {});
} }
@@ -47,6 +47,8 @@ import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters; import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.fineract.organisation.office.data.OfficeData;
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService; import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
@@ -90,6 +92,7 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
private final ConfigurationDomainService configurationDomainService; private final ConfigurationDomainService configurationDomainService;
private final CalendarReadPlatformService calendarReadPlatformService; private final CalendarReadPlatformService calendarReadPlatformService;
private final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd"); private final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
private final ColumnValidator columnValidator;
// data mappers // data mappers
private final CenterDataMapper centerMapper = new CenterDataMapper(); private final CenterDataMapper centerMapper = new CenterDataMapper();
@@ -104,7 +107,7 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
final ClientReadPlatformService clientReadPlatformService, final OfficeReadPlatformService officeReadPlatformService, final ClientReadPlatformService clientReadPlatformService, final OfficeReadPlatformService officeReadPlatformService,
final StaffReadPlatformService staffReadPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService, final StaffReadPlatformService staffReadPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService,
final PaginationParametersDataValidator paginationParametersDataValidator, final ConfigurationDomainService configurationDomainService, final PaginationParametersDataValidator paginationParametersDataValidator, final ConfigurationDomainService configurationDomainService,
final CalendarReadPlatformService calendarReadPlatformService) { final CalendarReadPlatformService calendarReadPlatformService, final ColumnValidator columnValidator) {
this.context = context; this.context = context;
this.clientReadPlatformService = clientReadPlatformService; this.clientReadPlatformService = clientReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
@@ -114,41 +117,48 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
this.paginationParametersDataValidator = paginationParametersDataValidator; this.paginationParametersDataValidator = paginationParametersDataValidator;
this.configurationDomainService = configurationDomainService; this.configurationDomainService = configurationDomainService;
this.calendarReadPlatformService = calendarReadPlatformService; this.calendarReadPlatformService = calendarReadPlatformService;
this.columnValidator = columnValidator;
} }
// 'g.' preffix because of ERROR 1052 (23000): Column 'column_name' in where // 'g.' preffix because of ERROR 1052 (23000): Column 'column_name' in where
// clause is ambiguous // clause is ambiguous
// caused by the same name of columns in m_office and m_group tables // caused by the same name of columns in m_office and m_group tables
private String getCenterExtraCriteria(final SearchParameters searchCriteria) { private String getCenterExtraCriteria(String schemaSl, List<Object> paramList,final SearchParameters searchCriteria) {
StringBuffer extraCriteria = new StringBuffer(200); StringBuffer extraCriteria = new StringBuffer(200);
extraCriteria.append(" and g.level_id = " + GroupTypes.CENTER.getId()); extraCriteria.append(" and g.level_id = " + GroupTypes.CENTER.getId());
String sqlQueryCriteria = searchCriteria.getSqlSearch(); String sqlQueryCriteria = searchCriteria.getSqlSearch();
if (StringUtils.isNotBlank(sqlQueryCriteria)) { if (StringUtils.isNotBlank(sqlQueryCriteria)) {
SQLInjectionValidator.validateSQLInput(sqlQueryCriteria);
sqlQueryCriteria = sqlQueryCriteria.replaceAll(" display_name ", " g.display_name "); sqlQueryCriteria = sqlQueryCriteria.replaceAll(" display_name ", " g.display_name ");
sqlQueryCriteria = sqlQueryCriteria.replaceAll("display_name ", "g.display_name "); sqlQueryCriteria = sqlQueryCriteria.replaceAll("display_name ", "g.display_name ");
extraCriteria.append(" and (").append(sqlQueryCriteria).append(") "); extraCriteria.append(" and (").append(sqlQueryCriteria).append(") ");
this.columnValidator.validateSqlInjection(schemaSl, sqlQueryCriteria);
} }
final Long officeId = searchCriteria.getOfficeId(); final Long officeId = searchCriteria.getOfficeId();
if (officeId != null) { if (officeId != null) {
extraCriteria.append(" and g.office_id = ").append(officeId); extraCriteria.append(" and g.office_id = ? ");
paramList.add(officeId);
} }
final String externalId = searchCriteria.getExternalId(); final String externalId = searchCriteria.getExternalId();
if (externalId != null) { if (externalId != null) {
extraCriteria.append(" and g.external_id = ").append(ApiParameterHelper.sqlEncodeString(externalId)); paramList.add(ApiParameterHelper.sqlEncodeString(externalId));
extraCriteria.append(" and g.external_id = ? ");
} }
final String name = searchCriteria.getName(); final String name = searchCriteria.getName();
if (name != null) { if (name != null) {
extraCriteria.append(" and g.display_name like ").append(ApiParameterHelper.sqlEncodeString(name + "%")); paramList.add(ApiParameterHelper.sqlEncodeString(name + "%"));
extraCriteria.append(" and g.display_name like ? ");
} }
final String hierarchy = searchCriteria.getHierarchy(); final String hierarchy = searchCriteria.getHierarchy();
if (hierarchy != null) { if (hierarchy != null) {
extraCriteria.append(" and o.hierarchy like ").append(ApiParameterHelper.sqlEncodeString(hierarchy + "%")); paramList.add(ApiParameterHelper.sqlEncodeString(hierarchy + "%"));
extraCriteria.append(" and o.hierarchy like ? ");
} }
if (StringUtils.isNotBlank(extraCriteria.toString())) { if (StringUtils.isNotBlank(extraCriteria.toString())) {
@@ -157,7 +167,8 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
final Long staffId = searchCriteria.getStaffId(); final Long staffId = searchCriteria.getStaffId();
if (staffId != null) { if (staffId != null) {
extraCriteria.append(" and g.staff_id = ").append(staffId); paramList.add(staffId);
extraCriteria.append(" and g.staff_id = ? ");
} }
return extraCriteria.toString(); return extraCriteria.toString();
@@ -372,9 +383,10 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append(this.centerMapper.schema()); sqlBuilder.append(this.centerMapper.schema());
sqlBuilder.append(" where o.hierarchy like ?"); sqlBuilder.append(" where o.hierarchy like ?");
List<Object> paramList = new ArrayList<>(
final String extraCriteria = getCenterExtraCriteria(searchParameters); Arrays.asList(hierarchySearchString));
final String extraCriteria = getCenterExtraCriteria(this.centerMapper.schema(), paramList, searchParameters);
this.columnValidator.validateSqlInjection(sqlBuilder.toString(), extraCriteria);
if (StringUtils.isNotBlank(extraCriteria)) { if (StringUtils.isNotBlank(extraCriteria)) {
sqlBuilder.append(" and (").append(extraCriteria).append(")"); sqlBuilder.append(" and (").append(extraCriteria).append(")");
} }
@@ -392,7 +404,7 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
final String sqlCountRows = "SELECT FOUND_ROWS()"; final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(),
new Object[] { hierarchySearchString }, this.centerMapper); paramList.toArray(), this.centerMapper);
} }
@Override @Override
@@ -407,9 +419,11 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
sqlBuilder.append("select "); sqlBuilder.append("select ");
sqlBuilder.append(this.centerMapper.schema()); sqlBuilder.append(this.centerMapper.schema());
sqlBuilder.append(" where o.hierarchy like ?"); sqlBuilder.append(" where o.hierarchy like ?");
List<Object> paramList = new ArrayList<>(
final String extraCriteria = getCenterExtraCriteria(searchParameters); Arrays.asList(hierarchySearchString));
final String extraCriteria = getCenterExtraCriteria(this.centerMapper.schema(), paramList, searchParameters);
this.columnValidator.validateSqlInjection(sqlBuilder.toString(), extraCriteria);
if (StringUtils.isNotBlank(extraCriteria)) { if (StringUtils.isNotBlank(extraCriteria)) {
sqlBuilder.append(" and (").append(extraCriteria).append(")"); sqlBuilder.append(" and (").append(extraCriteria).append(")");
} }
@@ -425,7 +439,7 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
} }
} }
return this.jdbcTemplate.query(sqlBuilder.toString(), this.centerMapper, new Object[] { hierarchySearchString }); return this.jdbcTemplate.query(sqlBuilder.toString(), this.centerMapper, paramList.toArray());
} }
@Override @Override
@@ -39,6 +39,8 @@ import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters; import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.fineract.organisation.office.data.OfficeData;
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService; import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
@@ -70,6 +72,7 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
private final AllGroupTypesDataMapper allGroupTypesDataMapper = new AllGroupTypesDataMapper(); private final AllGroupTypesDataMapper allGroupTypesDataMapper = new AllGroupTypesDataMapper();
private final PaginationHelper<GroupGeneralData> paginationHelper = new PaginationHelper<>(); private final PaginationHelper<GroupGeneralData> paginationHelper = new PaginationHelper<>();
private final PaginationParametersDataValidator paginationParametersDataValidator; private final PaginationParametersDataValidator paginationParametersDataValidator;
private final ColumnValidator columnValidator;
private final static Set<String> supportedOrderByValues = new HashSet<>(Arrays.asList("id", "name", "officeId", "officeName")); private final static Set<String> supportedOrderByValues = new HashSet<>(Arrays.asList("id", "name", "officeId", "officeName"));
@@ -78,7 +81,8 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
final CenterReadPlatformService centerReadPlatformService, final CenterReadPlatformService centerReadPlatformService,
final OfficeReadPlatformService officeReadPlatformService, final StaffReadPlatformService staffReadPlatformService, final OfficeReadPlatformService officeReadPlatformService, final StaffReadPlatformService staffReadPlatformService,
final CodeValueReadPlatformService codeValueReadPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService,
final PaginationParametersDataValidator paginationParametersDataValidator) { final PaginationParametersDataValidator paginationParametersDataValidator,
final ColumnValidator columnValidator) {
this.context = context; this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
this.centerReadPlatformService = centerReadPlatformService; this.centerReadPlatformService = centerReadPlatformService;
@@ -86,6 +90,7 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
this.staffReadPlatformService = staffReadPlatformService; this.staffReadPlatformService = staffReadPlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService; this.codeValueReadPlatformService = codeValueReadPlatformService;
this.paginationParametersDataValidator = paginationParametersDataValidator; this.paginationParametersDataValidator = paginationParametersDataValidator;
this.columnValidator = columnValidator;
} }
@Override @Override
@@ -147,9 +152,10 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append(this.allGroupTypesDataMapper.schema()); sqlBuilder.append(this.allGroupTypesDataMapper.schema());
sqlBuilder.append(" where o.hierarchy like ?"); sqlBuilder.append(" where o.hierarchy like ?");
List<Object> paramList = new ArrayList<>(
final String extraCriteria = getGroupExtraCriteria(searchParameters); Arrays.asList(hierarchySearchString));
final String extraCriteria = getGroupExtraCriteria(this.allGroupTypesDataMapper.schema(), paramList, searchParameters);
this.columnValidator.validateSqlInjection(sqlBuilder.toString(), extraCriteria);
if (StringUtils.isNotBlank(extraCriteria)) { if (StringUtils.isNotBlank(extraCriteria)) {
sqlBuilder.append(" and (").append(extraCriteria).append(")"); sqlBuilder.append(" and (").append(extraCriteria).append(")");
} }
@@ -167,7 +173,7 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
final String sqlCountRows = "SELECT FOUND_ROWS()"; final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(),
new Object[] { hierarchySearchString }, this.allGroupTypesDataMapper); paramList.toArray(), this.allGroupTypesDataMapper);
} }
@Override @Override
@@ -180,9 +186,9 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
sqlBuilder.append("select "); sqlBuilder.append("select ");
sqlBuilder.append(this.allGroupTypesDataMapper.schema()); sqlBuilder.append(this.allGroupTypesDataMapper.schema());
sqlBuilder.append(" where o.hierarchy like ?"); sqlBuilder.append(" where o.hierarchy like ?");
List<Object> paramList = new ArrayList<>(
final String extraCriteria = getGroupExtraCriteria(searchParameters); Arrays.asList(hierarchySearchString));
final String extraCriteria = getGroupExtraCriteria(this.allGroupTypesDataMapper.schema(), paramList, searchParameters);
if (StringUtils.isNotBlank(extraCriteria)) { if (StringUtils.isNotBlank(extraCriteria)) {
sqlBuilder.append(" and (").append(extraCriteria).append(")"); sqlBuilder.append(" and (").append(extraCriteria).append(")");
} }
@@ -195,45 +201,52 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
sqlBuilder.append(parameters.limitSql()); sqlBuilder.append(parameters.limitSql());
} }
return this.jdbcTemplate.query(sqlBuilder.toString(), this.allGroupTypesDataMapper, new Object[] { hierarchySearchString }); return this.jdbcTemplate.query(sqlBuilder.toString(), this.allGroupTypesDataMapper, paramList.toArray());
} }
// 'g.' preffix because of ERROR 1052 (23000): Column 'column_name' in where // 'g.' preffix because of ERROR 1052 (23000): Column 'column_name' in where
// clause is ambiguous // clause is ambiguous
// caused by the same name of columns in m_office and m_group tables // caused by the same name of columns in m_office and m_group tables
private String getGroupExtraCriteria(final SearchParameters searchCriteria) { private String getGroupExtraCriteria(String schemaSql, List<Object> paramList, final SearchParameters searchCriteria) {
StringBuffer extraCriteria = new StringBuffer(200); StringBuffer extraCriteria = new StringBuffer(200);
extraCriteria.append(" and g.level_Id = ").append(GroupTypes.GROUP.getId()); extraCriteria.append(" and g.level_Id = ").append(GroupTypes.GROUP.getId());
String sqlSearch = searchCriteria.getSqlSearch(); String sqlSearch = searchCriteria.getSqlSearch();
if (sqlSearch != null) { if (sqlSearch != null) {
SQLInjectionValidator.validateSQLInput(sqlSearch);
sqlSearch = sqlSearch.replaceAll(" display_name ", " g.display_name "); sqlSearch = sqlSearch.replaceAll(" display_name ", " g.display_name ");
sqlSearch = sqlSearch.replaceAll("display_name ", "g.display_name "); sqlSearch = sqlSearch.replaceAll("display_name ", "g.display_name ");
extraCriteria.append(" and ( ").append(sqlSearch).append(") "); extraCriteria.append(" and ( ").append(sqlSearch).append(") ");
this.columnValidator.validateSqlInjection(schemaSql, sqlSearch);
} }
final Long officeId = searchCriteria.getOfficeId(); final Long officeId = searchCriteria.getOfficeId();
if (officeId != null) { if (officeId != null) {
extraCriteria.append(" and g.office_id = ").append(officeId); paramList.add(officeId);
extraCriteria.append(" and g.office_id = ? ");
} }
final String externalId = searchCriteria.getExternalId(); final String externalId = searchCriteria.getExternalId();
if (externalId != null) { if (externalId != null) {
extraCriteria.append(" and g.external_id = ").append(ApiParameterHelper.sqlEncodeString(externalId)); paramList.add(ApiParameterHelper.sqlEncodeString(externalId));
extraCriteria.append(" and g.external_id = ? ");
} }
final String name = searchCriteria.getName(); final String name = searchCriteria.getName();
if (name != null) { if (name != null) {
extraCriteria.append(" and g.display_name like ").append(ApiParameterHelper.sqlEncodeString("%" + name + "%")); paramList.add(ApiParameterHelper.sqlEncodeString("%" + name + "%"));
extraCriteria.append(" and g.display_name like ? ");
} }
final String hierarchy = searchCriteria.getHierarchy(); final String hierarchy = searchCriteria.getHierarchy();
if (hierarchy != null) { if (hierarchy != null) {
extraCriteria.append(" and o.hierarchy like ").append(ApiParameterHelper.sqlEncodeString(hierarchy + "%")); paramList.add(ApiParameterHelper.sqlEncodeString(hierarchy + "%"));
extraCriteria.append(" and o.hierarchy like ? ");
} }
if (searchCriteria.isStaffIdPassed()) { if (searchCriteria.isStaffIdPassed()) {
extraCriteria.append(" and g.staff_id = ").append(searchCriteria.getStaffId()); paramList.add(searchCriteria.getStaffId());
extraCriteria.append(" and g.staff_id = ? ");
} }
if (StringUtils.isNotBlank(extraCriteria.toString())) { if (StringUtils.isNotBlank(extraCriteria.toString())) {
@@ -242,7 +255,8 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
final Long staffId = searchCriteria.getStaffId(); final Long staffId = searchCriteria.getStaffId();
if (staffId != null) { if (staffId != null) {
extraCriteria.append(" and g.staff_id = ").append(staffId); paramList.add(staffId);
extraCriteria.append(" and g.staff_id = ? ");
} }
if(searchCriteria.isOrphansOnly()){ if(searchCriteria.isOrphansOnly()){
@@ -44,6 +44,8 @@ import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters; import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
@@ -153,6 +155,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private final LoanUtilService loanUtilService; private final LoanUtilService loanUtilService;
private final ConfigurationDomainService configurationDomainService; private final ConfigurationDomainService configurationDomainService;
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService; private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
private final ColumnValidator columnValidator;
@Autowired @Autowired
public LoanReadPlatformServiceImpl(final PlatformSecurityContext context, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, public LoanReadPlatformServiceImpl(final PlatformSecurityContext context, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
@@ -166,7 +169,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final FloatingRatesReadPlatformService floatingRatesReadPlatformService, final LoanUtilService loanUtilService, final FloatingRatesReadPlatformService floatingRatesReadPlatformService, final LoanUtilService loanUtilService,
final ConfigurationDomainService configurationDomainService, final ConfigurationDomainService configurationDomainService,
final AccountDetailsReadPlatformService accountDetailsReadPlatformService, final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
final LoanRepositoryWrapper loanRepositoryWrapper) { final LoanRepositoryWrapper loanRepositoryWrapper, final ColumnValidator columnValidator) {
this.context = context; this.context = context;
this.loanRepositoryWrapper = loanRepositoryWrapper ; this.loanRepositoryWrapper = loanRepositoryWrapper ;
this.applicationCurrencyRepository = applicationCurrencyRepository; this.applicationCurrencyRepository = applicationCurrencyRepository;
@@ -187,6 +190,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
this.loanUtilService = loanUtilService; this.loanUtilService = loanUtilService;
this.configurationDomainService = configurationDomainService; this.configurationDomainService = configurationDomainService;
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService; this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
this.columnValidator = columnValidator;
} }
@Override @Override
@@ -281,7 +285,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
String sqlQueryCriteria = searchParameters.getSqlSearch(); String sqlQueryCriteria = searchParameters.getSqlSearch();
if (StringUtils.isNotBlank(sqlQueryCriteria)) { if (StringUtils.isNotBlank(sqlQueryCriteria)) {
SQLInjectionValidator.validateSQLInput(sqlQueryCriteria);
sqlQueryCriteria = sqlQueryCriteria.replaceAll("accountNo", "l.account_no"); sqlQueryCriteria = sqlQueryCriteria.replaceAll("accountNo", "l.account_no");
this.columnValidator.validateSqlInjection(sqlBuilder.toString(), sqlQueryCriteria);
sqlBuilder.append(" and (").append(sqlQueryCriteria).append(")"); sqlBuilder.append(" and (").append(sqlQueryCriteria).append(")");
} }
@@ -32,6 +32,7 @@ import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityType; import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityType;
import org.apache.fineract.infrastructure.entityaccess.service.FineractEntityAccessUtil; import org.apache.fineract.infrastructure.entityaccess.service.FineractEntityAccessUtil;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.charge.data.ChargeData; import org.apache.fineract.portfolio.charge.data.ChargeData;
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
@@ -121,7 +122,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
String sql = "select " + rm.schema(); String sql = "select " + rm.schema();
if ((inClause != null) && (!(inClause.trim().isEmpty()))) { if ((inClause != null) && (!(inClause.trim().isEmpty()))) {
sql += " where lp.id in ( " + inClause + " ) "; sql += " where lp.id in ("+inClause+") ";
SQLInjectionValidator.validateSQLInput(inClause);
} }
return this.jdbcTemplate.query(sql, rm, new Object[] {}); return this.jdbcTemplate.query(sql, rm, new Object[] {});
@@ -534,17 +536,17 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
final LoanProductMapper rm = new LoanProductMapper(null, null); final LoanProductMapper rm = new LoanProductMapper(null, null);
String sql = "select " + rm.loanProductSchema() + " where lp.currency_code='" + currencyCode + "'"; String sql = "select " + rm.loanProductSchema() + " where lp.currency_code= ? ";
// Check if branch specific products are enabled. If yes, fetch only // Check if branch specific products are enabled. If yes, fetch only
// products mapped to current user's office // products mapped to current user's office
String inClause = fineractEntityAccessUtil String inClause = fineractEntityAccessUtil
.getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled(FineractEntityType.LOAN_PRODUCT); .getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled(FineractEntityType.LOAN_PRODUCT);
if ((inClause != null) && (!(inClause.trim().isEmpty()))) { if ((inClause != null) && (!(inClause.trim().isEmpty()))) {
sql += " and id in ( " + inClause + " ) "; sql += " and id in (" + inClause + ") ";
} }
return this.jdbcTemplate.query(sql, rm, new Object[] {}); return this.jdbcTemplate.query(sql, rm, new Object[] {currencyCode});
} }
@Override @Override
@@ -82,7 +82,8 @@ public class MeetingReadPlatformServiceImpl implements MeetingReadPlatformServic
final MeetingDataMapper rm = new MeetingDataMapper(); final MeetingDataMapper rm = new MeetingDataMapper();
String sql = rm.schema() + " where ci.entity_id = ? and ci.entity_type_enum = ? "; String sql = rm.schema() + " where ci.entity_id = ? and ci.entity_type_enum = ? ";
if (limit != null && limit > 0) { if (limit != null && limit > 0) {
sql = sql + " order by m.meeting_date desc " + " limit " + limit; sql = sql + " order by m.meeting_date desc " + " limit ? ";
return this.jdbcTemplate.query(sql, rm, new Object[] { entityId, entityTypeId, limit });
} }
return this.jdbcTemplate.query(sql, rm, new Object[] { entityId, entityTypeId }); return this.jdbcTemplate.query(sql, rm, new Object[] { entityId, entityTypeId });
@@ -20,7 +20,10 @@ package org.apache.fineract.portfolio.note.service;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.data.EnumOptionData;
@@ -86,14 +89,16 @@ public class NoteReadPlatformServiceImpl implements NoteReadPlatformService {
final NoteType noteType = NoteType.fromInt(noteTypeId); final NoteType noteType = NoteType.fromInt(noteTypeId);
try { try {
final NoteMapper rm = new NoteMapper(); final NoteMapper rm = new NoteMapper();
String conditionSql = getResourceCondition(noteType); List<Object> paramList = new ArrayList<>(
Arrays.asList(noteId, resourceId));
String conditionSql = getResourceCondition(noteType, paramList);
if (StringUtils.isNotBlank(conditionSql)) { if (StringUtils.isNotBlank(conditionSql)) {
conditionSql = " and " + conditionSql; conditionSql = " and " + conditionSql;
} }
final String sql = rm.schema() + " where n.id = ? " + conditionSql + " order by n.created_date DESC"; final String sql = rm.schema() + " where n.id = ? " + conditionSql + " order by n.created_date DESC";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { noteId, resourceId }); return this.jdbcTemplate.queryForObject(sql, rm, paramList.toArray());
} catch (final EmptyResultDataAccessException e) { } catch (final EmptyResultDataAccessException e) {
throw new NoteNotFoundException(noteId, resourceId, noteType.name().toLowerCase()); throw new NoteNotFoundException(noteId, resourceId, noteType.name().toLowerCase());
} }
@@ -103,22 +108,26 @@ public class NoteReadPlatformServiceImpl implements NoteReadPlatformService {
public Collection<NoteData> retrieveNotesByResource(final Long resourceId, final Integer noteTypeId) { public Collection<NoteData> retrieveNotesByResource(final Long resourceId, final Integer noteTypeId) {
final NoteType noteType = NoteType.fromInt(noteTypeId); final NoteType noteType = NoteType.fromInt(noteTypeId);
final NoteMapper rm = new NoteMapper(); final NoteMapper rm = new NoteMapper();
final String conditionSql = getResourceCondition(noteType); List<Object> paramList = new ArrayList<>(
Arrays.asList(resourceId));
final String conditionSql = getResourceCondition(noteType, paramList);
final String sql = rm.schema() + " where " + conditionSql + " order by n.created_date DESC"; final String sql = rm.schema() + " where " + conditionSql + " order by n.created_date DESC";
return this.jdbcTemplate.query(sql, rm, new Object[] { resourceId }); return this.jdbcTemplate.query(sql, rm, paramList.toArray());
} }
public static String getResourceCondition(final NoteType noteType) { public static String getResourceCondition(final NoteType noteType, List<Object> paramList) {
String conditionSql = ""; String conditionSql = "";
switch (noteType) { switch (noteType) {
case CLIENT: case CLIENT:
conditionSql = " n.client_id = ? and note_type_enum = " + NoteType.CLIENT.getValue(); paramList.add(NoteType.CLIENT.getValue());
conditionSql = " n.client_id = ? and note_type_enum = ?";
break; break;
case LOAN: case LOAN:
conditionSql = " n.loan_id = ? and ( n.note_type_enum = " + NoteType.LOAN.getValue() + " or n.note_type_enum = " paramList.add(NoteType.LOAN.getValue());
+ NoteType.LOAN_TRANSACTION.getValue() + " )"; paramList.add(NoteType.LOAN_TRANSACTION.getValue());
conditionSql = " n.loan_id = ? and ( n.note_type_enum = ? or n.note_type_enum = ? )";
break; break;
case LOAN_TRANSACTION: case LOAN_TRANSACTION:
conditionSql = " n.loan_transaction_id = ? "; conditionSql = " n.loan_transaction_id = ? ";
@@ -241,21 +241,20 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
@Override @Override
public Collection<SavingsAccountAnnualFeeData> retrieveChargesWithAnnualFeeDue() { public Collection<SavingsAccountAnnualFeeData> retrieveChargesWithAnnualFeeDue() {
final String sql = "select " + this.chargeDueMapper.schema() + " where sac.charge_due_date is not null and sac.charge_time_enum = " final String sql = "select " + this.chargeDueMapper.schema() + " where sac.charge_due_date is not null and sac.charge_time_enum = ? "
+ ChargeTimeType.ANNUAL_FEE.getValue() + " and sac.charge_due_date <= NOW() and sa.status_enum = " + " and sac.charge_due_date <= NOW() and sa.status_enum = ? ";
+ SavingsAccountStatusType.ACTIVE.getValue();
return this.jdbcTemplate.query(sql, this.chargeDueMapper, new Object[] {}); return this.jdbcTemplate.query(sql, this.chargeDueMapper, new Object[] {ChargeTimeType.ANNUAL_FEE.getValue(), SavingsAccountStatusType.ACTIVE.getValue()});
} }
@Override @Override
public Collection<SavingsAccountAnnualFeeData> retrieveChargesWithDue() { public Collection<SavingsAccountAnnualFeeData> retrieveChargesWithDue() {
final String sql = "select " final String sql = "select "
+ this.chargeDueMapper.schema() + this.chargeDueMapper.schema()
+ " where sac.charge_due_date is not null and sac.charge_due_date <= NOW() and sac.waived = 0 and sac.is_paid_derived=0 and sac.is_active=1 and sa.status_enum = " + " where sac.charge_due_date is not null and sac.charge_due_date <= NOW() and sac.waived = 0 and sac.is_paid_derived=0 and sac.is_active=1 and sa.status_enum = ? "
+ SavingsAccountStatusType.ACTIVE.getValue() + " order by sac.charge_due_date "; + " order by sac.charge_due_date ";
return this.jdbcTemplate.query(sql, this.chargeDueMapper, new Object[] {}); return this.jdbcTemplate.query(sql, this.chargeDueMapper, new Object[] {SavingsAccountStatusType.ACTIVE.getValue()});
} }
@@ -39,6 +39,7 @@ import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.organisation.staff.service.StaffReadPlatformService; import org.apache.fineract.organisation.staff.service.StaffReadPlatformService;
@@ -106,6 +107,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
private final PaginationHelper<SavingsAccountData> paginationHelper = new PaginationHelper<>(); private final PaginationHelper<SavingsAccountData> paginationHelper = new PaginationHelper<>();
private final EntityDatatableChecksReadService entityDatatableChecksReadService; private final EntityDatatableChecksReadService entityDatatableChecksReadService;
private final ColumnValidator columnValidator;
@Autowired @Autowired
public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
@@ -113,7 +115,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final SavingsProductReadPlatformService savingProductReadPlatformService, final SavingsProductReadPlatformService savingProductReadPlatformService,
final StaffReadPlatformService staffReadPlatformService, final SavingsDropdownReadPlatformService dropdownReadPlatformService, final StaffReadPlatformService staffReadPlatformService, final SavingsDropdownReadPlatformService dropdownReadPlatformService,
final ChargeReadPlatformService chargeReadPlatformService, final ChargeReadPlatformService chargeReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService) { final EntityDatatableChecksReadService entityDatatableChecksReadService, final ColumnValidator columnValidator) {
this.context = context; this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
this.clientReadPlatformService = clientReadPlatformService; this.clientReadPlatformService = clientReadPlatformService;
@@ -127,6 +129,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
// this.annualFeeMapper = new SavingsAccountAnnualFeeMapper(); // this.annualFeeMapper = new SavingsAccountAnnualFeeMapper();
this.chargeReadPlatformService = chargeReadPlatformService; this.chargeReadPlatformService = chargeReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService; this.entityDatatableChecksReadService = entityDatatableChecksReadService;
this.columnValidator = columnValidator;
} }
@Override @Override
@@ -179,6 +182,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
String sqlQueryCriteria = searchParameters.getSqlSearch(); String sqlQueryCriteria = searchParameters.getSqlSearch();
if (StringUtils.isNotBlank(sqlQueryCriteria)) { if (StringUtils.isNotBlank(sqlQueryCriteria)) {
sqlQueryCriteria = sqlQueryCriteria.replaceAll("accountNo", "sa.account_no"); sqlQueryCriteria = sqlQueryCriteria.replaceAll("accountNo", "sa.account_no");
this.columnValidator.validateSqlInjection(sqlBuilder.toString(), sqlQueryCriteria);
sqlBuilder.append(" and (").append(sqlQueryCriteria).append(")"); sqlBuilder.append(" and (").append(sqlQueryCriteria).append(")");
} }
@@ -278,7 +278,7 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
this.context.authenticatedUser(); this.context.authenticatedUser();
String sql = "select " + this.savingsProductRowMapper.schema() + " where sp.currency_code='" + currencyCode + "'"; String sql = "select " + this.savingsProductRowMapper.schema() + " where sp.currency_code= ? ";
// Check if branch specific products are enabled. If yes, fetch only // Check if branch specific products are enabled. If yes, fetch only
// products mapped to current user's office // products mapped to current user's office
@@ -288,6 +288,6 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
sql += " and id in ( " + inClause + " ) "; sql += " and id in ( " + inClause + " ) ";
} }
return this.jdbcTemplate.query(sql, this.savingsProductRowMapper); return this.jdbcTemplate.query(sql, this.savingsProductRowMapper, new Object[] {currencyCode});
} }
} }