mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
Merge branch 'master' of https://github.com/wenshao/druid
This commit is contained in:
@@ -17,69 +17,69 @@ package com.alibaba.druid.wall;
|
||||
|
||||
import static com.alibaba.druid.wall.spi.WallVisitorUtils.loadResource;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
|
||||
import com.alibaba.druid.wall.spi.WallVisitorUtils;
|
||||
|
||||
public class WallConfig implements WallConfigMBean {
|
||||
|
||||
private boolean noneBaseStatementAllow = false;
|
||||
private boolean noneBaseStatementAllow = false;
|
||||
|
||||
private boolean callAllow = true;
|
||||
private boolean selelctAllow = true;
|
||||
private boolean selectIntoAllow = true;
|
||||
private boolean selectIntoOutfileAllow = false;
|
||||
private boolean selectWhereAlwayTrueCheck = true;
|
||||
private boolean selectHavingAlwayTrueCheck = true;
|
||||
private boolean selectUnionCheck = true;
|
||||
private boolean callAllow = true;
|
||||
private boolean selelctAllow = true;
|
||||
private boolean selectIntoAllow = true;
|
||||
private boolean selectIntoOutfileAllow = false;
|
||||
private boolean selectWhereAlwayTrueCheck = true;
|
||||
private boolean selectHavingAlwayTrueCheck = true;
|
||||
private boolean selectUnionCheck = true;
|
||||
|
||||
private boolean selectAllColumnAllow = true;
|
||||
private boolean selectAllColumnAllow = true;
|
||||
|
||||
private boolean deleteAllow = true;
|
||||
private boolean deleteWhereAlwayTrueCheck = true;
|
||||
private boolean deleteAllow = true;
|
||||
private boolean deleteWhereAlwayTrueCheck = true;
|
||||
|
||||
private boolean updateAllow = true;
|
||||
private boolean updateWhereAlayTrueCheck = true;
|
||||
private boolean updateAllow = true;
|
||||
private boolean updateWhereAlayTrueCheck = true;
|
||||
|
||||
private boolean insertAllow = true;
|
||||
private boolean mergeAllow = true;
|
||||
private boolean insertAllow = true;
|
||||
private boolean mergeAllow = true;
|
||||
|
||||
private boolean multiStatementAllow = false;
|
||||
private boolean multiStatementAllow = false;
|
||||
|
||||
private boolean truncateAllow = false;
|
||||
private boolean truncateAllow = false;
|
||||
|
||||
private boolean commentAllow = false;
|
||||
private boolean commentAllow = false;
|
||||
|
||||
private boolean describeAllow = false;
|
||||
private boolean describeAllow = false;
|
||||
|
||||
private boolean schemaCheck = true;
|
||||
private boolean tableCheck = true;
|
||||
private boolean functionCheck = true;
|
||||
private boolean objectCheck = true;
|
||||
private boolean variantCheck = true;
|
||||
private boolean schemaCheck = true;
|
||||
private boolean tableCheck = true;
|
||||
private boolean functionCheck = true;
|
||||
private boolean objectCheck = true;
|
||||
private boolean variantCheck = true;
|
||||
|
||||
private boolean mustParameterized = false;
|
||||
private boolean mustParameterized = false;
|
||||
|
||||
private boolean doPrivilegedAllow = false;
|
||||
private boolean doPrivilegedAllow = false;
|
||||
|
||||
protected final Set<String> permitFunctions = new HashSet<String>();
|
||||
protected final Set<String> permitTables = new HashSet<String>();
|
||||
protected final Set<String> permitSchemas = new HashSet<String>();
|
||||
protected final Set<String> permitVariants = new HashSet<String>();
|
||||
protected final Set<String> permitObjects = new HashSet<String>();
|
||||
protected final Set<String> denyFunctions = new ConcurrentSkipListSet<String>();
|
||||
protected final Set<String> denyTables = new ConcurrentSkipListSet<String>();
|
||||
protected final Set<String> denySchemas = new ConcurrentSkipListSet<String>();
|
||||
protected final Set<String> denyVariants = new ConcurrentSkipListSet<String>();
|
||||
protected final Set<String> denyObjects = new ConcurrentSkipListSet<String>();
|
||||
|
||||
protected final Set<String> readOnlyTables = new HashSet<String>();
|
||||
protected final Set<String> readOnlyTables = new ConcurrentSkipListSet<String>();
|
||||
|
||||
private String dir;
|
||||
private String dir;
|
||||
|
||||
private boolean inited;
|
||||
private boolean inited;
|
||||
|
||||
private String tenantTablePattern;
|
||||
private String tenantColumn;
|
||||
private String tenantTablePattern;
|
||||
private String tenantColumn;
|
||||
|
||||
private boolean wrapAllow = true;
|
||||
private boolean metadataAllow = true;
|
||||
private boolean wrapAllow = true;
|
||||
private boolean metadataAllow = true;
|
||||
|
||||
public WallConfig(){
|
||||
|
||||
@@ -159,11 +159,11 @@ public class WallConfig implements WallConfigMBean {
|
||||
dir = dir.substring(0, dir.length() - 1);
|
||||
}
|
||||
|
||||
loadResource(this.permitVariants, dir + "/permit-variant.txt");
|
||||
loadResource(this.permitSchemas, dir + "/permit-schema.txt");
|
||||
loadResource(this.permitFunctions, dir + "/permit-function.txt");
|
||||
loadResource(this.permitTables, dir + "/permit-table.txt");
|
||||
loadResource(this.permitObjects, dir + "/permit-object.txt");
|
||||
loadResource(this.denyVariants, dir + "/deny-variant.txt");
|
||||
loadResource(this.denySchemas, dir + "/deny-schema.txt");
|
||||
loadResource(this.denyFunctions, dir + "/deny-function.txt");
|
||||
loadResource(this.denyTables, dir + "/deny-table.txt");
|
||||
loadResource(this.denyObjects, dir + "/deny-object.txt");
|
||||
loadResource(this.readOnlyTables, dir + "/readonly-table.txt");
|
||||
}
|
||||
|
||||
@@ -357,30 +357,38 @@ public class WallConfig implements WallConfigMBean {
|
||||
this.commentAllow = commentAllow;
|
||||
}
|
||||
|
||||
public Set<String> getPermitFunctions() {
|
||||
return permitFunctions;
|
||||
public Set<String> getDenyFunctions() {
|
||||
return denyFunctions;
|
||||
}
|
||||
|
||||
public Set<String> getPermitTables() {
|
||||
return permitTables;
|
||||
public Set<String> getDenyTables() {
|
||||
return denyTables;
|
||||
}
|
||||
|
||||
public Set<String> getPermitSchemas() {
|
||||
return permitSchemas;
|
||||
public Set<String> getDenySchemas() {
|
||||
return denySchemas;
|
||||
}
|
||||
|
||||
public Set<String> getPermitVariants() {
|
||||
return permitVariants;
|
||||
public Set<String> getDenyVariants() {
|
||||
return denyVariants;
|
||||
}
|
||||
|
||||
public Set<String> getPermitObjects() {
|
||||
return permitObjects;
|
||||
public Set<String> getDenyObjects() {
|
||||
return denyObjects;
|
||||
}
|
||||
|
||||
public Set<String> getReadOnlyTables() {
|
||||
return readOnlyTables;
|
||||
}
|
||||
|
||||
public void addReadOnlyTable(String tableName) {
|
||||
this.readOnlyTables.add(tableName);
|
||||
}
|
||||
|
||||
public boolean isReadOnly(String tableName) {
|
||||
return this.readOnlyTables.contains(tableName);
|
||||
}
|
||||
|
||||
public boolean isMustParameterized() {
|
||||
return mustParameterized;
|
||||
}
|
||||
@@ -389,31 +397,31 @@ public class WallConfig implements WallConfigMBean {
|
||||
this.mustParameterized = mustParameterized;
|
||||
}
|
||||
|
||||
public boolean isPermitObjects(String name) {
|
||||
public boolean isDenyObjects(String name) {
|
||||
if (!objectCheck) {
|
||||
return false;
|
||||
}
|
||||
|
||||
name = WallVisitorUtils.form(name);
|
||||
return permitObjects.contains(name);
|
||||
return denyObjects.contains(name);
|
||||
}
|
||||
|
||||
public boolean isPermitSchema(String name) {
|
||||
public boolean isDenySchema(String name) {
|
||||
if (!schemaCheck) {
|
||||
return false;
|
||||
}
|
||||
|
||||
name = WallVisitorUtils.form(name);
|
||||
return this.permitSchemas.contains(name);
|
||||
return this.denySchemas.contains(name);
|
||||
}
|
||||
|
||||
public boolean isPermitFunction(String name) {
|
||||
public boolean isDenyFunction(String name) {
|
||||
if (!functionCheck) {
|
||||
return false;
|
||||
}
|
||||
|
||||
name = WallVisitorUtils.form(name);
|
||||
return this.permitFunctions.contains(name);
|
||||
return this.denyFunctions.contains(name);
|
||||
}
|
||||
|
||||
public boolean isCallAllow() {
|
||||
|
||||
@@ -113,22 +113,22 @@ public interface WallConfigMBean {
|
||||
|
||||
void setCommentAllow(boolean commentAllow);
|
||||
|
||||
Set<String> getPermitFunctions();
|
||||
Set<String> getDenyFunctions();
|
||||
|
||||
Set<String> getPermitTables();
|
||||
Set<String> getDenyTables();
|
||||
|
||||
Set<String> getPermitSchemas();
|
||||
Set<String> getDenySchemas();
|
||||
|
||||
Set<String> getPermitVariants();
|
||||
Set<String> getDenyVariants();
|
||||
|
||||
Set<String> getPermitObjects();
|
||||
Set<String> getDenyObjects();
|
||||
|
||||
Set<String> getReadOnlyTables();
|
||||
|
||||
boolean isPermitObjects(String name);
|
||||
boolean isDenyObjects(String name);
|
||||
|
||||
boolean isPermitSchema(String name);
|
||||
boolean isDenySchema(String name);
|
||||
|
||||
boolean isPermitFunction(String name);
|
||||
boolean isDenyFunction(String name);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.alibaba.druid.wall;
|
||||
|
||||
public class WallContext {
|
||||
|
||||
private final static ThreadLocal<WallContext> contextLocal = new ThreadLocal<WallContext>();
|
||||
|
||||
private WallSqlStat sqlState;
|
||||
|
||||
public static WallContext createIfNotExists() {
|
||||
WallContext context = contextLocal.get();
|
||||
if (context == null) {
|
||||
context = new WallContext();
|
||||
contextLocal.set(context);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
public static WallContext current() {
|
||||
return contextLocal.get();
|
||||
}
|
||||
|
||||
public static void clearContext() {
|
||||
contextLocal.remove();
|
||||
}
|
||||
|
||||
public WallSqlStat getSqlState() {
|
||||
return sqlState;
|
||||
}
|
||||
|
||||
public void setSqlState(WallSqlStat sqlState) {
|
||||
this.sqlState = sqlState;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.alibaba.druid.wall;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
|
||||
|
||||
public class WallDenyStat {
|
||||
|
||||
private volatile long denyCount;
|
||||
|
||||
private volatile long lastDenyTimeMillis;
|
||||
|
||||
private volatile long resetCount;
|
||||
|
||||
final static AtomicLongFieldUpdater<WallDenyStat> denyCountUpdater = AtomicLongFieldUpdater.newUpdater(WallDenyStat.class,
|
||||
"denyCount");
|
||||
|
||||
final static AtomicLongFieldUpdater<WallDenyStat> resetCountUpdater = AtomicLongFieldUpdater.newUpdater(WallDenyStat.class,
|
||||
"resetCount");
|
||||
|
||||
public long incrementAndGetDenyCount() {
|
||||
lastDenyTimeMillis = System.currentTimeMillis();
|
||||
return denyCountUpdater.incrementAndGet(this);
|
||||
}
|
||||
|
||||
public long getDenyCount() {
|
||||
return denyCount;
|
||||
}
|
||||
|
||||
public Date getLastDenyTime() {
|
||||
if (lastDenyTimeMillis <= 0) {
|
||||
return null;
|
||||
}
|
||||
return new Date(lastDenyTimeMillis);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
lastDenyTimeMillis = 0;
|
||||
denyCount = 0;
|
||||
resetCountUpdater.incrementAndGet(this);
|
||||
}
|
||||
|
||||
public long getResetCount() {
|
||||
return this.resetCount;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -37,7 +37,7 @@ import com.alibaba.druid.support.logging.LogFactory;
|
||||
import com.alibaba.druid.util.JdbcUtils;
|
||||
import com.alibaba.druid.wall.spi.MySqlWallProvider;
|
||||
import com.alibaba.druid.wall.spi.OracleWallProvider;
|
||||
import com.alibaba.druid.wall.spi.SQLServerProvider;
|
||||
import com.alibaba.druid.wall.spi.SQLServerWallProvider;
|
||||
import com.alibaba.druid.wall.violation.SyntaxErrorViolation;
|
||||
|
||||
public class WallFilter extends FilterAdapter implements WallFilterMBean {
|
||||
@@ -86,10 +86,10 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
|
||||
provider = new OracleWallProvider(config);
|
||||
} else if (JdbcUtils.SQL_SERVER.equals(dbType) || JdbcUtils.JTDS.equals(dbType)) {
|
||||
if (config == null) {
|
||||
config = new WallConfig(SQLServerProvider.DEFAULT_CONFIG_DIR);
|
||||
config = new WallConfig(SQLServerWallProvider.DEFAULT_CONFIG_DIR);
|
||||
}
|
||||
|
||||
provider = new SQLServerProvider(config);
|
||||
provider = new SQLServerWallProvider(config);
|
||||
} else {
|
||||
throw new IllegalStateException("dbType not support : " + dbType + ", url " + dataSource.getUrl());
|
||||
}
|
||||
@@ -159,139 +159,235 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
|
||||
|
||||
@Override
|
||||
public void statement_addBatch(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
|
||||
sql = check(sql);
|
||||
chain.statement_addBatch(statement, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
chain.statement_addBatch(statement, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
|
||||
String sql, int autoGeneratedKeys) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, autoGeneratedKeys);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, autoGeneratedKeys);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
|
||||
String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
|
||||
String sql, int resultSetType, int resultSetConcurrency,
|
||||
int resultSetHoldability) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency,
|
||||
resultSetHoldability);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency,
|
||||
resultSetHoldability);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
|
||||
String sql, int[] columnIndexes) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, columnIndexes);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, columnIndexes);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
|
||||
String sql, String[] columnNames) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, columnNames);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareStatement(connection, sql, columnNames);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
|
||||
int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
|
||||
int resultSetType, int resultSetConcurrency,
|
||||
int resultSetHoldability) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency,
|
||||
resultSetHoldability);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
// //////////////
|
||||
|
||||
@Override
|
||||
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, autoGeneratedKeys);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, autoGeneratedKeys);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, columnIndexes);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, columnIndexes);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, columnNames);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_execute(statement, sql, columnNames);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeQuery(statement, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeQuery(statement, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, autoGeneratedKeys);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, autoGeneratedKeys);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, columnIndexes);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, columnIndexes);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
|
||||
throws SQLException {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, columnNames);
|
||||
WallContext.createIfNotExists();
|
||||
try {
|
||||
sql = check(sql);
|
||||
return chain.statement_executeUpdate(statement, sql, columnNames);
|
||||
} finally {
|
||||
WallContext.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
public String check(String sql) throws SQLException {
|
||||
@@ -355,7 +451,7 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
|
||||
if (isLogViolation()) {
|
||||
LOG.error("not support method : Connection.getMetdataData");
|
||||
}
|
||||
|
||||
|
||||
if (throwException) {
|
||||
throw new WallSQLException("not support method : Connection.getMetdataData");
|
||||
} else {
|
||||
@@ -369,4 +465,16 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
|
||||
public long getViolationCount() {
|
||||
return this.violationCount.get();
|
||||
}
|
||||
|
||||
public void resetViolationCount() {
|
||||
this.violationCount.set(0);
|
||||
}
|
||||
|
||||
public void clearWhiteList() {
|
||||
this.provider.clearCache();
|
||||
}
|
||||
|
||||
public boolean checkValid(String sql) {
|
||||
return provider.checkValid(sql);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +39,10 @@ public interface WallFilterMBean {
|
||||
String check(String sql) throws SQLException;
|
||||
|
||||
long getViolationCount();
|
||||
|
||||
void resetViolationCount();
|
||||
|
||||
void clearWhiteList();
|
||||
|
||||
boolean checkValid(String sql);
|
||||
}
|
||||
|
||||
@@ -19,33 +19,40 @@ import java.security.PrivilegedAction;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.parser.NotAllowCommentException;
|
||||
import com.alibaba.druid.sql.parser.ParserException;
|
||||
import com.alibaba.druid.sql.parser.SQLStatementParser;
|
||||
import com.alibaba.druid.sql.parser.Token;
|
||||
import com.alibaba.druid.sql.visitor.ExportParameterVisitor;
|
||||
import com.alibaba.druid.util.LRUCache;
|
||||
import com.alibaba.druid.wall.spi.WallVisitorUtils;
|
||||
import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;
|
||||
import com.alibaba.druid.wall.violation.SyntaxErrorViolation;
|
||||
|
||||
public abstract class WallProvider {
|
||||
|
||||
// Dummy value to associate with an Object in the backing Map
|
||||
private static final Object PRESENT = new Object();
|
||||
private LinkedHashMap<String, WallSqlStat> whiteList;
|
||||
|
||||
private LinkedHashMap<String, Object> whiteList;
|
||||
private int whileListMaxSize = 1024;
|
||||
|
||||
private int whileListMaxSize = 1024;
|
||||
private int whiteSqlMaxLength = 1024; // 1k
|
||||
|
||||
private int whiteSqlMaxLength = 1024; // 1k
|
||||
protected final WallConfig config;
|
||||
|
||||
protected final WallConfig config;
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private static final ThreadLocal<Boolean> privileged = new ThreadLocal<Boolean>();
|
||||
|
||||
private static final ThreadLocal<Boolean> privileged = new ThreadLocal<Boolean>();
|
||||
private final ConcurrentMap<String, WallDenyStat> deniedTables = new ConcurrentHashMap<String, WallDenyStat>();
|
||||
private final ConcurrentMap<String, WallDenyStat> deniedFunctions = new ConcurrentHashMap<String, WallDenyStat>();
|
||||
private final ConcurrentMap<String, WallDenyStat> deniedSchemas = new ConcurrentHashMap<String, WallDenyStat>();
|
||||
|
||||
public final WallDenyStat commentDeniedStat = new WallDenyStat();
|
||||
|
||||
public WallProvider(WallConfig config){
|
||||
this.config = config;
|
||||
@@ -59,10 +66,10 @@ public abstract class WallProvider {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (whiteList == null) {
|
||||
whiteList = new LRUCache<String, Object>(whileListMaxSize);
|
||||
whiteList = new LRUCache<String, WallSqlStat>(whileListMaxSize);
|
||||
}
|
||||
|
||||
whiteList.put(sql, PRESENT);
|
||||
whiteList.put(sql, new WallSqlStat());
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
@@ -83,6 +90,10 @@ public abstract class WallProvider {
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
clearWhiteList();
|
||||
}
|
||||
|
||||
public void clearWhiteList() {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (whiteList != null) {
|
||||
@@ -93,19 +104,23 @@ public abstract class WallProvider {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean whiteContains(String sql) {
|
||||
public WallSqlStat getWhiteSql(String sql) {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
if (whiteList == null) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
return whiteList.get(sql) != null;
|
||||
return whiteList.get(sql);
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean whiteContains(String sql) {
|
||||
return getWhiteSql(sql) != null;
|
||||
}
|
||||
|
||||
public abstract SQLStatementParser createParser(String sql);
|
||||
|
||||
public abstract WallVisitor createWallVisitor();
|
||||
@@ -113,7 +128,110 @@ public abstract class WallProvider {
|
||||
public abstract ExportParameterVisitor createExportParameterVisitor();
|
||||
|
||||
public boolean checkValid(String sql) {
|
||||
return check(sql).getViolations().isEmpty();
|
||||
WallCheckResult result = check(sql);
|
||||
return result.getViolations().isEmpty();
|
||||
}
|
||||
|
||||
public void incrementCommentDeniedCount() {
|
||||
this.commentDeniedStat.incrementAndGetDenyCount();
|
||||
}
|
||||
|
||||
public boolean checkDenyFunction(String functionName) {
|
||||
if (functionName == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
functionName = functionName.toLowerCase();
|
||||
if (getConfig().getDenyFunctions().contains(functionName)) {
|
||||
WallDenyStat denyStat = this.deniedFunctions.get(functionName);
|
||||
if (denyStat == null) {
|
||||
this.deniedFunctions.putIfAbsent(functionName, new WallDenyStat());
|
||||
denyStat = this.deniedFunctions.get(functionName);
|
||||
}
|
||||
denyStat.incrementAndGetDenyCount();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkDenySchema(String schemaName) {
|
||||
if (schemaName == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
schemaName = schemaName.toLowerCase();
|
||||
if (getConfig().getDenySchemas().contains(schemaName)) {
|
||||
WallDenyStat denyStat = this.deniedSchemas.get(schemaName);
|
||||
if (denyStat == null) {
|
||||
this.deniedSchemas.putIfAbsent(schemaName, new WallDenyStat());
|
||||
denyStat = this.deniedSchemas.get(schemaName);
|
||||
}
|
||||
denyStat.incrementAndGetDenyCount();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkDenyTable(String tableName) {
|
||||
if (tableName == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
tableName = WallVisitorUtils.form(tableName);
|
||||
if (getConfig().getDenyTables().contains(tableName)) {
|
||||
WallDenyStat denyStat = this.deniedTables.get(tableName);
|
||||
if (denyStat == null) {
|
||||
this.deniedTables.putIfAbsent(tableName, new WallDenyStat());
|
||||
denyStat = this.deniedTables.get(tableName);
|
||||
}
|
||||
denyStat.incrementAndGetDenyCount();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkReadOnlyTable(String tableName) {
|
||||
if (tableName == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
tableName = WallVisitorUtils.form(tableName);
|
||||
if (getConfig().isReadOnly(tableName)) {
|
||||
WallDenyStat denyStat = this.deniedTables.get(tableName);
|
||||
if (denyStat == null) {
|
||||
this.deniedTables.putIfAbsent(tableName, new WallDenyStat());
|
||||
denyStat = this.deniedTables.get(tableName);
|
||||
}
|
||||
denyStat.incrementAndGetDenyCount();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public WallDenyStat getDenniedTableStat(String tableName) {
|
||||
if (tableName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String formName = WallVisitorUtils.form(tableName);
|
||||
return deniedTables.get(formName);
|
||||
}
|
||||
|
||||
public WallDenyStat getDenniedSchemaStat(String schemaName) {
|
||||
if (schemaName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String formName = WallVisitorUtils.form(schemaName);
|
||||
return deniedSchemas.get(formName);
|
||||
}
|
||||
|
||||
public WallDenyStat getCommentDenyStat() {
|
||||
return this.commentDeniedStat;
|
||||
}
|
||||
|
||||
public WallCheckResult check(String sql) {
|
||||
@@ -124,19 +242,24 @@ public abstract class WallProvider {
|
||||
}
|
||||
|
||||
// first step, check whiteList
|
||||
boolean isWhite = whiteContains(sql);
|
||||
if (isWhite) {
|
||||
WallSqlStat sqlStat = getWhiteSql(sql);
|
||||
if (sqlStat != null) {
|
||||
sqlStat.incrementAndGetExecuteCount();
|
||||
return result;
|
||||
}
|
||||
|
||||
SQLStatementParser parser = createParser(sql);
|
||||
|
||||
if (!config.isCommentAllow()) {
|
||||
parser.getLexer().setAllowComment(false); // permit comment
|
||||
parser.getLexer().setAllowComment(false); // deny comment
|
||||
}
|
||||
|
||||
try {
|
||||
parser.parseStatementList(result.getStatementList());
|
||||
} catch (NotAllowCommentException e) {
|
||||
result.getViolations().add(new SyntaxErrorViolation(e, sql));
|
||||
incrementCommentDeniedCount();
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
result.getViolations().add(new SyntaxErrorViolation(e, sql));
|
||||
return result;
|
||||
@@ -176,13 +299,13 @@ public abstract class WallProvider {
|
||||
result.getViolations().addAll(visitor.getViolations());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static boolean ispPivileged() {
|
||||
Boolean value = privileged.get();
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return value.booleanValue();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.alibaba.druid.wall;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
|
||||
|
||||
public class WallSqlStat {
|
||||
|
||||
private volatile long executeCount;
|
||||
|
||||
final static AtomicLongFieldUpdater<WallSqlStat> executeCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class,
|
||||
"executeCount");
|
||||
|
||||
public long incrementAndGetExecuteCount() {
|
||||
return executeCountUpdater.incrementAndGet(this);
|
||||
}
|
||||
|
||||
public long getExecuteCount() {
|
||||
return executeCount;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@ package com.alibaba.druid.wall;
|
||||
|
||||
import com.alibaba.druid.wall.spi.MySqlWallProvider;
|
||||
import com.alibaba.druid.wall.spi.OracleWallProvider;
|
||||
import com.alibaba.druid.wall.spi.SQLServerProvider;
|
||||
import com.alibaba.druid.wall.spi.SQLServerWallProvider;
|
||||
|
||||
public class WallUtils {
|
||||
|
||||
@@ -42,12 +42,12 @@ public class WallUtils {
|
||||
}
|
||||
|
||||
public static boolean isValidateSqlServer(String sql) {
|
||||
SQLServerProvider provider = new SQLServerProvider();
|
||||
SQLServerWallProvider provider = new SQLServerWallProvider();
|
||||
return provider.checkValid(sql);
|
||||
}
|
||||
|
||||
public static boolean isValidateSqlServer(String sql, WallConfig config) {
|
||||
SQLServerProvider provider = new SQLServerProvider(config);
|
||||
SQLServerWallProvider provider = new SQLServerWallProvider(config);
|
||||
return provider.checkValid(sql);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public interface WallVisitor extends SQLASTVisitor {
|
||||
|
||||
void addViolation(Violation violation);
|
||||
|
||||
boolean isPermitTable(String name);
|
||||
boolean isDenyTable(String name);
|
||||
|
||||
String toSQL(SQLObject obj);
|
||||
}
|
||||
|
||||
@@ -237,13 +237,12 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermitTable(String name) {
|
||||
public boolean isDenyTable(String name) {
|
||||
if (!config.isTableCheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
name = WallVisitorUtils.form(name);
|
||||
return config.getPermitTables().contains(name);
|
||||
return !this.provider.checkDenyTable(name);
|
||||
}
|
||||
|
||||
public void preVisit(SQLObject x) {
|
||||
|
||||
@@ -83,7 +83,7 @@ public class OracleWallVisitor extends OracleASTVisitorAdapter implements WallVi
|
||||
public boolean visit(SQLIdentifierExpr x) {
|
||||
String name = x.getName();
|
||||
name = WallVisitorUtils.form(name);
|
||||
if (config.isVariantCheck() && config.getPermitVariants().contains(name)) {
|
||||
if (config.isVariantCheck() && config.getDenyVariants().contains(name)) {
|
||||
getViolations().add(new IllegalSQLObjectViolation(toSQL(x)));
|
||||
}
|
||||
return true;
|
||||
@@ -112,8 +112,7 @@ public class OracleWallVisitor extends OracleASTVisitorAdapter implements WallVi
|
||||
}
|
||||
|
||||
public boolean visit(OracleSelectTableReference x) {
|
||||
WallVisitorUtils.check(this, x);
|
||||
return true;
|
||||
return WallVisitorUtils.check(this, x);
|
||||
}
|
||||
|
||||
public boolean visit(SQLExprTableSource x) {
|
||||
@@ -158,7 +157,7 @@ public class OracleWallVisitor extends OracleASTVisitorAdapter implements WallVi
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermitTable(String name) {
|
||||
public boolean isDenyTable(String name) {
|
||||
if (!config.isTableCheck()) {
|
||||
return false;
|
||||
}
|
||||
@@ -167,7 +166,7 @@ public class OracleWallVisitor extends OracleASTVisitorAdapter implements WallVi
|
||||
if (name.startsWith("v$") || name.startsWith("v_$")) {
|
||||
return true;
|
||||
}
|
||||
return config.getPermitTables().contains(name);
|
||||
return !this.provider.checkDenyTable(name);
|
||||
}
|
||||
|
||||
public void preVisit(SQLObject x) {
|
||||
|
||||
+3
-3
@@ -30,18 +30,18 @@ import com.alibaba.druid.wall.WallVisitor;
|
||||
* @version 1.0, 2012-3-17
|
||||
* @see
|
||||
*/
|
||||
public class SQLServerProvider extends WallProvider {
|
||||
public class SQLServerWallProvider extends WallProvider {
|
||||
|
||||
public final static String DEFAULT_CONFIG_DIR = "META-INF/druid/wall/sqlserver";
|
||||
|
||||
/**
|
||||
* @param config
|
||||
*/
|
||||
public SQLServerProvider(){
|
||||
public SQLServerWallProvider(){
|
||||
this(new WallConfig(DEFAULT_CONFIG_DIR));
|
||||
}
|
||||
|
||||
public SQLServerProvider(WallConfig config){
|
||||
public SQLServerWallProvider(WallConfig config){
|
||||
super(config);
|
||||
}
|
||||
|
||||
@@ -80,13 +80,12 @@ public class SQLServerWallVisitor extends SQLServerASTVisitorAdapter implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermitTable(String name) {
|
||||
public boolean isDenyTable(String name) {
|
||||
if (!config.isTableCheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
name = WallVisitorUtils.form(name);
|
||||
return config.getPermitTables().contains(name);
|
||||
return !this.provider.checkDenyTable(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,7 +96,7 @@ public class SQLServerWallVisitor extends SQLServerASTVisitorAdapter implements
|
||||
public boolean visit(SQLIdentifierExpr x) {
|
||||
String name = x.getName();
|
||||
name = WallVisitorUtils.form(name);
|
||||
if (config.isVariantCheck() && config.getPermitVariants().contains(name)) {
|
||||
if (config.isVariantCheck() && config.getDenyVariants().contains(name)) {
|
||||
getViolations().add(new IllegalSQLObjectViolation(toSQL(x)));
|
||||
}
|
||||
return true;
|
||||
@@ -238,10 +237,10 @@ public class SQLServerWallVisitor extends SQLServerASTVisitorAdapter implements
|
||||
|
||||
@Override
|
||||
public boolean visit(SQLServerObjectReferenceExpr x) {
|
||||
if (x.getSchema() != null && config.isPermitSchema(x.getSchema())) {
|
||||
if (x.getSchema() != null && !provider.checkDenySchema(x.getSchema())) {
|
||||
this.getViolations().add(new IllegalSQLObjectViolation(this.toSQL(x)));
|
||||
}
|
||||
if (x.getDatabase() != null && config.isPermitSchema(x.getDatabase())) {
|
||||
if (x.getDatabase() != null && !provider.checkDenySchema(x.getDatabase())) {
|
||||
this.getViolations().add(new IllegalSQLObjectViolation(this.toSQL(x)));
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -69,7 +69,7 @@ import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;
|
||||
|
||||
public class WallVisitorUtils {
|
||||
|
||||
private final static Log LOG = LogFactory.getLog(WallVisitorUtils.class);
|
||||
private final static Log LOG = LogFactory.getLog(WallVisitorUtils.class);
|
||||
|
||||
public static void check(WallVisitor visitor, SQLInListExpr x) {
|
||||
|
||||
@@ -348,11 +348,9 @@ public class WallVisitorUtils {
|
||||
tableName = ((SQLName) tableNameExpr).getSimleName();
|
||||
}
|
||||
|
||||
if (tableName != null) {
|
||||
tableName = form(tableName);
|
||||
if (visitor.getConfig().getReadOnlyTables().contains(tableName)) {
|
||||
addViolation(visitor, tableSource);
|
||||
}
|
||||
boolean readOnlyValid = visitor.getProvider().checkReadOnlyTable(tableName);
|
||||
if (!readOnlyValid) {
|
||||
addViolation(visitor, tableSource);
|
||||
}
|
||||
} else if (tableSource instanceof SQLJoinTableSource) {
|
||||
SQLJoinTableSource join = (SQLJoinTableSource) tableSource;
|
||||
@@ -777,44 +775,54 @@ public class WallVisitorUtils {
|
||||
|
||||
String methodName = x.getMethodName();
|
||||
|
||||
if (visitor.getConfig().isPermitFunction(methodName.toLowerCase())) {
|
||||
if (!visitor.getProvider().checkDenyFunction(methodName)) {
|
||||
addViolation(visitor, x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void checkSchema(WallVisitor visitor, SQLExpr x) {
|
||||
private static boolean checkSchema(WallVisitor visitor, SQLExpr x) {
|
||||
if (x instanceof SQLName) {
|
||||
String owner = ((SQLName) x).getSimleName();
|
||||
owner = WallVisitorUtils.form(owner);
|
||||
if (visitor.getConfig().isPermitSchema(owner)) {
|
||||
if (!visitor.getProvider().checkDenySchema(owner)) {
|
||||
addViolation(visitor, x);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (visitor.getConfig().isPermitObjects(owner)) {
|
||||
if (visitor.getConfig().isDenyObjects(owner)) {
|
||||
addViolation(visitor, x);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// if (ownerExpr instanceof SQLPropertyExpr) {
|
||||
if (x instanceof SQLPropertyExpr) {
|
||||
checkSchema(visitor, ((SQLPropertyExpr) x).getOwner());
|
||||
return checkSchema(visitor, ((SQLPropertyExpr) x).getOwner());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void check(WallVisitor visitor, SQLExprTableSource x) {
|
||||
public static boolean check(WallVisitor visitor, SQLExprTableSource x) {
|
||||
SQLExpr expr = x.getExpr();
|
||||
|
||||
if (expr instanceof SQLPropertyExpr) {
|
||||
checkSchema(visitor, ((SQLPropertyExpr) expr).getOwner());
|
||||
boolean checkResult = checkSchema(visitor, ((SQLPropertyExpr) expr).getOwner());
|
||||
if (!checkResult) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (expr instanceof SQLName) {
|
||||
String tableName = ((SQLName) expr).getSimleName();
|
||||
if (visitor.isPermitTable(tableName)) {
|
||||
if (visitor.isDenyTable(tableName)) {
|
||||
addViolation(visitor, x);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void addViolation(WallVisitor visitor, SQLObject x) {
|
||||
@@ -919,7 +927,7 @@ public class WallVisitorUtils {
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("load oracle permit tables errror", e);
|
||||
LOG.error("load oracle deny tables errror", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user