Skip to content

Commit f0d9139

Browse files
dbulahovstbischof
authored andcommitted
Check used Funtions in sql statment within guard #8
Signed-off-by: <[email protected]>
1 parent 743eac9 commit f0d9139

File tree

4 files changed

+155
-18
lines changed

4 files changed

+155
-18
lines changed

guard/api/src/main/java/org/eclipse/daanse/sql/guard/api/SqlGuardFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
*/
1414
package org.eclipse.daanse.sql.guard.api;
1515

16+
import java.util.List;
17+
1618
import org.eclipse.daanse.sql.guard.api.elements.DatabaseCatalog;
1719

1820
public interface SqlGuardFactory {
1921

20-
SqlGuard create(String currentCatalogName, String currentSchemaName, DatabaseCatalog databaseCatalog);
22+
SqlGuard create(String currentCatalogName, String currentSchemaName, DatabaseCatalog databaseCatalog, List<String> whitelistFunctionsPatterns);
2123
}

guard/jsqltranspiler/src/main/java/org/eclipse/daanse/sql/guard/jsqltranspiler/TranspilerSqlGuard.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414

1515
package org.eclipse.daanse.sql.guard.jsqltranspiler;
1616

17+
import java.util.ArrayList;
1718
import java.util.List;
1819
import java.util.Set;
20+
import java.util.regex.Pattern;
1921

2022
import org.eclipse.daanse.sql.guard.api.SqlGuard;
2123
import org.eclipse.daanse.sql.guard.api.elements.DatabaseCatalog;
@@ -51,11 +53,13 @@ public class TranspilerSqlGuard implements SqlGuard {
5153
private static final String UPDATE_IS_NOT_PERMITTED = "UPDATE is not permitted.";
5254
private static final String INSERT_IS_NOT_PERMITTED = "INSERT is not permitted.";
5355
private static final String NOTHING_WAS_SELECTED = "Nothing was selected.";
56+
private static final String QUERY_HAS_DISAllOWED_FUNCTIONS = "Query has disallowed functions.";
5457
private static final Logger LOGGER = LoggerFactory.getLogger(TranspilerSqlGuard.class);
5558
private JdbcMetaData jdbcMetaDataToCopy;
59+
private List<String> whitelistFunctionsPatterns = new ArrayList<String>();
5660

57-
public TranspilerSqlGuard(String currentCatalogName, String currentSchemaName, DatabaseCatalog databaseCatalog) {
58-
61+
public TranspilerSqlGuard(String currentCatalogName, String currentSchemaName, DatabaseCatalog databaseCatalog, List<String> whitelistFunctionsPatterns) {
62+
this.whitelistFunctionsPatterns = whitelistFunctionsPatterns;
5963
jdbcMetaDataToCopy = calculateMetaData(currentCatalogName, currentSchemaName, databaseCatalog);
6064

6165
}
@@ -114,6 +118,28 @@ public String guard(String sqlStr) throws GuardException {
114118
final List<Expression> functions = resolver.getFunctions();
115119
final Set<String> functionNames = resolver.getFlatFunctionNames();
116120

121+
List<String> allowedFunctions = new ArrayList<>();
122+
List<String> disallowedFunctions = new ArrayList<>();
123+
124+
for (String function : functionNames) {
125+
boolean isAllowed = false;
126+
for (String pattern : whitelistFunctionsPatterns) {
127+
if (Pattern.matches(pattern, function)) {
128+
isAllowed = true;
129+
break;
130+
}
131+
}
132+
if (isAllowed) {
133+
allowedFunctions.add(function);
134+
} else {
135+
disallowedFunctions.add(function);
136+
}
137+
}
138+
if (!disallowedFunctions.isEmpty()) {
139+
LOGGER.atInfo().log(QUERY_HAS_DISAllOWED_FUNCTIONS);
140+
throw new GuardException(QUERY_HAS_DISAllOWED_FUNCTIONS);
141+
}
142+
117143
// we can finally resolve for the actually returned columns
118144
JSQLColumResolver columResolver = new JSQLColumResolver(jdbcMetaDataToCopy);
119145
columResolver.setErrorMode(JdbcMetaData.ErrorMode.STRICT);

guard/jsqltranspiler/src/main/java/org/eclipse/daanse/sql/guard/jsqltranspiler/TranspilerSqlGuardFactory.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
*/
1414
package org.eclipse.daanse.sql.guard.jsqltranspiler;
1515

16+
import java.util.List;
17+
1618
import org.eclipse.daanse.sql.guard.api.SqlGuard;
1719
import org.eclipse.daanse.sql.guard.api.SqlGuardFactory;
1820
import org.eclipse.daanse.sql.guard.api.elements.DatabaseCatalog;
@@ -23,8 +25,8 @@
2325
public class TranspilerSqlGuardFactory implements SqlGuardFactory {
2426

2527
@Override
26-
public SqlGuard create(String currentCatalogName, String currentSchemaName, DatabaseCatalog databaseCatalog) {
27-
return new TranspilerSqlGuard(currentCatalogName, currentSchemaName, databaseCatalog);
28+
public SqlGuard create(String currentCatalogName, String currentSchemaName, DatabaseCatalog databaseCatalog, List<String> whitelistFunctionsPatterns) {
29+
return new TranspilerSqlGuard(currentCatalogName, currentSchemaName, databaseCatalog, whitelistFunctionsPatterns);
2830
}
2931

3032
}

guard/jsqltranspiler/src/test/java/org/eclipse/daanse/sql/guard/jsqltranspiler/SqlGuardTest.java

Lines changed: 120 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
import org.eclipse.daanse.sql.guard.api.elements.DatabaseColumn;
2828
import org.eclipse.daanse.sql.guard.api.elements.DatabaseSchema;
2929
import org.eclipse.daanse.sql.guard.api.elements.DatabaseTable;
30+
import org.eclipse.daanse.sql.guard.api.exception.GuardException;
3031
import org.eclipse.daanse.sql.guard.api.exception.UnresolvableObjectsGuardException;
31-
import org.junit.jupiter.api.Disabled;
3232
import org.junit.jupiter.api.Test;
3333
import org.osgi.test.common.annotation.InjectService;
3434

@@ -52,8 +52,20 @@ public class SqlGuardTest {
5252

5353
private static final String SQL_WITH_FUNCTION = "select trim(foo.name) from foo";
5454

55+
private static final String SQL_WITH_ALLOWED_FUNCTION = "select %s(foo.name) from foo";
56+
57+
private static final String SQL_WITH_ALLOWED_FUNCTION_IN_WHERE = "select foo.name from foo where %s(foo.name) = 1";
58+
59+
private static final String SQL_WITH_ALLOWED_FUNCTION_IN_HAVING = "select foo.name from foo group by foo.name HAVING %s(foo.id) > 5";
60+
5561
private static final String SQL_WITH_FUNCTION_EXPECTED = "SELECT Trim( foo.name ) FROM sch.foo";
5662

63+
private static final String SQL_WITH_ALLOWED_FUNCTION_EXPECTED = "SELECT %s(foo.name) FROM sch.foo";
64+
65+
private static final String SQL_WITH_ALLOWED_FUNCTION__IN_WHERE_EXPECTED = "SELECT foo.name FROM sch.foo WHERE %s(foo.name) = 1";
66+
67+
private static final String SQL_WITH_ALLOWED_FUNCTION__IN_HAVING_EXPECTED = "SELECT foo.name FROM sch.foo GROUP BY foo.name HAVING %s(foo.id) > 5";
68+
5769
private static final String SQL_WITH_HAVING_WRONG_COLUMN = """
5870
select %s(foo.id) from foo group by foo.name having foo.name1 = 'tets'""";
5971

@@ -140,11 +152,15 @@ public class SqlGuardTest {
140152

141153
private static final List<String> AGGREGATIONS = List.of("sum", "count", "distinctcount", "avg");
142154

155+
private static final List<String> ALLOWED_FUNCTIONS = List.of("DeleteAll", "InsertAll", "UpdateAll", "Modify", "deleteAll", "insertAll", "updateAll", "modify");
156+
157+
private static final List<String> NOT_ALLOWED_FUNCTIONS = List.of("NotDeleteAll", "NotInsertAll", "NotUpdateAll", "NotModify", "notDeleteAll", "notInsertAll", "notUpdateAll", "notModify");
158+
143159
@Test
144160
void testName(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
145161
DatabaseCatalog databaseCatalog = schemaWithTwoTableTwoCol();
146162

147-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
163+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
148164

149165
String result = guard.guard(SELECT_FROM_FOO);
150166

@@ -155,7 +171,7 @@ void testName(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
155171
void testInnerJoin(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
156172
DatabaseCatalog databaseCatalog = schemaWithTwoTableTwoCol();
157173

158-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
174+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
159175

160176
String result = guard.guard(SELECT_INNER_JOIN);
161177
assertEquals(SELECT_INNER_JOIN_EXPECTED, result);
@@ -165,7 +181,7 @@ void testInnerJoin(@InjectService SqlGuardFactory sqlGuardFactory) throws Except
165181
void testInnerJoin1(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
166182
DatabaseCatalog databaseCatalog = schemaWithTwoTableTwoCol();
167183

168-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
184+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
169185

170186
String result = guard.guard(SELECT_INNER_JOIN_C_D);
171187

@@ -176,7 +192,7 @@ void testInnerJoin1(@InjectService SqlGuardFactory sqlGuardFactory) throws Excep
176192
void testInnerJoin2(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
177193
DatabaseCatalog databaseCatalog = schemaWithTwoTableTwoCol();
178194

179-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
195+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
180196

181197
String result = guard.guard(SELECT_INNER_JOIN_D);
182198

@@ -187,7 +203,7 @@ void testInnerJoin2(@InjectService SqlGuardFactory sqlGuardFactory) throws Excep
187203
void testTripleSelect(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
188204
DatabaseCatalog databaseCatalog = schemaWithTwoTableTwoCol();
189205

190-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
206+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
191207

192208
String result = guard.guard(TRIPLE_SELECT_SQL);
193209

@@ -198,7 +214,7 @@ void testTripleSelect(@InjectService SqlGuardFactory sqlGuardFactory) throws Exc
198214
void testWhere(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
199215
DatabaseCatalog databaseCatalog = schemaWithTwoTableTwoCol();
200216

201-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
217+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
202218

203219
String result = guard.guard(SQL_WITH_IN);
204220

@@ -209,7 +225,7 @@ void testWhere(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception
209225
void testAdditionalColumn(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
210226
DatabaseCatalog databaseCatalog = schemaWithOneTable2Col();
211227

212-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
228+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
213229

214230
String result = guard.guard(SQL_WITH_CUSTOM_COLUMN);
215231

@@ -220,7 +236,7 @@ void testAdditionalColumn(@InjectService SqlGuardFactory sqlGuardFactory) throws
220236
void testUndefinedTable(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
221237

222238
DatabaseCatalog databaseCatalog = schemaWithTwoTableTwoCol();
223-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
239+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
224240

225241
assertThrows(UnresolvableObjectsGuardException.class, () -> guard.guard(SQL_WITH_WRONG_TABLE));
226242

@@ -230,7 +246,7 @@ void testUndefinedTable(@InjectService SqlGuardFactory sqlGuardFactory) throws E
230246
void test(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
231247
DatabaseCatalog databaseCatalog = schemaWithOneTable2Col();
232248

233-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
249+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
234250

235251
RuntimeException thrown = assertThrows(RuntimeException.class, () -> guard.guard(SIMPLE_SQL_WITH_WRONG_TABLE));
236252
assertEquals(TABLE_FOO1_DOES_NOT_EXIST_IN_THE_GIVEN_SCHEMA_SCH, thrown.getMessage());
@@ -241,7 +257,7 @@ void testGroup(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception
241257

242258
DatabaseCatalog databaseCatalog = schemaWithOneTable2Col();
243259

244-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
260+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
245261

246262
String result = guard.guard(SQL_WITH_GROUP);
247263

@@ -253,7 +269,8 @@ void testGroupAggregation(@InjectService SqlGuardFactory sqlGuardFactory) throws
253269

254270
DatabaseCatalog databaseCatalog = schemaWithOneTable2Col();
255271

256-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
272+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, AGGREGATIONS);
273+
257274

258275
for (String agg : AGGREGATIONS) {
259276
String result = guard.guard(String.format(SQL_WITH_AGG, agg));
@@ -281,12 +298,102 @@ void testGroupAggregation(@InjectService SqlGuardFactory sqlGuardFactory) throws
281298
}
282299
}
283300

301+
@Test
302+
void testAllowedFunctions(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
303+
304+
DatabaseCatalog databaseCatalog = schemaWithOneTable2Col();
305+
306+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, ALLOWED_FUNCTIONS);
307+
for (String fun : ALLOWED_FUNCTIONS) {
308+
String result = guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION, fun));
309+
310+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION_EXPECTED, fun), result);
311+
312+
result = guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_WHERE, fun));
313+
314+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION__IN_WHERE_EXPECTED, fun), result);
315+
316+
result = guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_HAVING, fun));
317+
318+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION__IN_HAVING_EXPECTED, fun), result);
319+
}
320+
//allowed all
321+
guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of(".*"));
322+
for (String fun : ALLOWED_FUNCTIONS) {
323+
String result = guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION, fun));
324+
325+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION_EXPECTED, fun), result);
326+
327+
result = guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_WHERE, fun));
328+
329+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION__IN_WHERE_EXPECTED, fun), result);
330+
331+
result = guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_HAVING, fun));
332+
333+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION__IN_HAVING_EXPECTED, fun), result);
334+
}
335+
guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of("Delete.*", "Insert.*", "UpdateAll", "Modify.*", "delete.*", "insert.*", "update.*", "modify"));
336+
for (String fun : ALLOWED_FUNCTIONS) {
337+
String result = guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION, fun));
338+
339+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION_EXPECTED, fun), result);
340+
341+
result = guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_WHERE, fun));
342+
343+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION__IN_WHERE_EXPECTED, fun), result);
344+
345+
result = guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_HAVING, fun));
346+
347+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION__IN_HAVING_EXPECTED, fun), result);
348+
}
349+
}
350+
351+
@Test
352+
void testDeleteAllFunctionsNotAllowed(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
353+
354+
DatabaseCatalog databaseCatalog = schemaWithOneTable2Col();
355+
//all function not allowed
356+
final SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
357+
for (String fun : ALLOWED_FUNCTIONS) {
358+
assertThrows(GuardException.class, () -> guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION, fun)));
359+
assertThrows(GuardException.class, () -> guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_WHERE, fun)));
360+
assertThrows(GuardException.class, () -> guard.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_HAVING, fun)));
361+
}
362+
//all functions with wrong names are allowed only . all good functions are not allowed
363+
final SqlGuard guard1 = sqlGuardFactory.create("", SCH, databaseCatalog, List.of("Dalete.*", "Iinsert.*", "UupdateAll", "Moodify.*", "ddelete.*", "insertt.*", "uppdate.*", "moodify"));
364+
for (String fun : ALLOWED_FUNCTIONS) {
365+
assertThrows(GuardException.class, () -> guard1.guard(String.format(SQL_WITH_ALLOWED_FUNCTION, fun)));
366+
assertThrows(GuardException.class, () -> guard1.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_WHERE, fun)));
367+
assertThrows(GuardException.class, () -> guard1.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_HAVING, fun)));
368+
}
369+
//all functions with wrong names are allowed only . all good functions are not allowed
370+
final SqlGuard guard2 = sqlGuardFactory.create("", SCH, databaseCatalog, ALLOWED_FUNCTIONS);
371+
for (String fun : NOT_ALLOWED_FUNCTIONS) {
372+
assertThrows(GuardException.class, () -> guard2.guard(String.format(SQL_WITH_ALLOWED_FUNCTION, fun)));
373+
assertThrows(GuardException.class, () -> guard2.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_WHERE, fun)));
374+
assertThrows(GuardException.class, () -> guard2.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_HAVING, fun)));
375+
}
376+
for (String fun : ALLOWED_FUNCTIONS) {
377+
String result = guard2.guard(String.format(SQL_WITH_ALLOWED_FUNCTION, fun));
378+
379+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION_EXPECTED, fun), result);
380+
381+
result = guard2.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_WHERE, fun));
382+
383+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION__IN_WHERE_EXPECTED, fun), result);
384+
385+
result = guard2.guard(String.format(SQL_WITH_ALLOWED_FUNCTION_IN_HAVING, fun));
386+
387+
assertEquals(String.format(SQL_WITH_ALLOWED_FUNCTION__IN_HAVING_EXPECTED, fun), result);
388+
}
389+
}
390+
284391
@Test
285392
void testFunctions(@InjectService SqlGuardFactory sqlGuardFactory) throws Exception {
286393

287394
DatabaseCatalog databaseCatalog = schemaWithOneTable2Col();
288395

289-
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog);
396+
SqlGuard guard = sqlGuardFactory.create("", SCH, databaseCatalog, List.of());
290397

291398
String result = guard.guard(SQL_WITH_FUNCTION);
292399

0 commit comments

Comments
 (0)