From 11d0871fa09419432072a6dfd394f2df24ceea2d Mon Sep 17 00:00:00 2001 From: Cason <1125193113@qq.com> Date: Thu, 29 Jun 2023 21:28:54 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E5=85=A8=E5=B1=80=E9=85=8D=E7=BD=AEsafe-mode=EF=BC=8C=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E7=A7=9F=E6=88=B7=E6=8F=92=E4=BB=B6id=E5=BC=95?= =?UTF-8?q?=E8=B5=B7=E7=9A=84sql=E6=B3=A8=E5=85=A5=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E4=B8=BAapply=E5=92=8Chaving=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E7=9A=84=E4=BC=A0=E5=8F=82=E5=81=9A=E4=BA=86=E8=BF=9B=E4=B8=80?= =?UTF-8?q?=E6=AD=A5=E5=AE=89=E5=85=A8=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/mybatisplus/QueryCondition.java | 27 ++++++ .../StreamPluginAutoConfiguration.java | 15 +++ .../SqTenantLineInnerInterceptor.java | 64 +++++++++++++ .../engine/utils/SqlInjectionUtilSq.java | 45 +++++++++ .../MybatisPlusTestApplication.java | 2 +- .../mybatisplus/pojo/po/ProductCategory.java | 41 +++++++++ .../mybatisplus/pojo/po/ProductInfo.java | 44 +++++++++ .../safe/SqlInjectionTenantTest.java | 91 +++++++++++++++++++ .../safe/SqlInjectionWrapperTest.java | 64 +++++++++++++ .../src/test/resources/application.yml | 1 + .../src/test/resources/data.sql | 23 +++++ .../src/test/resources/schema.sql | 22 ++++- 12 files changed, 437 insertions(+), 2 deletions(-) create mode 100644 stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java create mode 100644 stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/utils/SqlInjectionUtilSq.java create mode 100644 stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductCategory.java create mode 100644 stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductInfo.java create mode 100644 stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java create mode 100644 stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java index 92d07e69..5a2bf083 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java @@ -32,6 +32,8 @@ import org.dromara.streamquery.stream.core.lambda.LambdaExecutable; import org.dromara.streamquery.stream.core.lambda.LambdaHelper; import org.dromara.streamquery.stream.core.optional.Opp; import org.dromara.streamquery.stream.core.stream.Steam; +import org.dromara.streamquery.stream.plugin.mybatisplus.engine.configuration.StreamPluginAutoConfiguration; +import org.dromara.streamquery.stream.plugin.mybatisplus.engine.utils.SqlInjectionUtilSq; import java.util.Collection; import java.util.Map; @@ -266,4 +268,29 @@ public class QueryCondition extends LambdaQueryWrapper { SharedString.emptyString(), SharedString.emptyString()); } + + @Override + public LambdaQueryWrapper apply(boolean condition, String applySql, Object... values) { + if (StreamPluginAutoConfiguration.isSafeModeEnabled() && SqlInjectionUtilSq.check(applySql)) { + throw new IllegalArgumentException("SQL Injection attempt detected in 'apply'"); + } + + return this.maybeDo( + condition, + () -> + this.appendSqlSegments( + WrapperKeyword.APPLY, () -> this.formatSqlMaybeWithParam(applySql, null, values))); + } + + @Override + public LambdaQueryWrapper having(boolean condition, String sqlHaving, Object... params) { + if (StreamPluginAutoConfiguration.isSafeModeEnabled() && SqlInjectionUtilSq.check(sqlHaving)) { + throw new IllegalArgumentException("SQL Injection attempt detected in 'having'"); + } + return this.maybeDo( + condition, + () -> + this.appendSqlSegments( + SqlKeyword.HAVING, () -> this.formatSqlMaybeWithParam(sqlHaving, null, params))); + } } diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/configuration/StreamPluginAutoConfiguration.java b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/configuration/StreamPluginAutoConfiguration.java index 00e43462..525d9831 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/configuration/StreamPluginAutoConfiguration.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/configuration/StreamPluginAutoConfiguration.java @@ -31,9 +31,11 @@ import org.dromara.streamquery.stream.plugin.mybatisplus.engine.handler.JsonPost import org.dromara.streamquery.stream.plugin.mybatisplus.engine.mapper.DynamicMapperHandler; import org.dromara.streamquery.stream.plugin.mybatisplus.engine.methods.SaveOneSql; import org.dromara.streamquery.stream.plugin.mybatisplus.engine.methods.UpdateOneSql; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.core.annotation.Order; +import org.springframework.core.env.Environment; import java.util.List; @@ -47,6 +49,19 @@ public class StreamPluginAutoConfiguration { private static final String CURRENT_NAMESPACE = LambdaHelper.getPropertyName(TableInfo::getCurrentNamespace); + private static boolean safeModeEnabled; + + @Autowired + public void setEnvironment(Environment environment) { + safeModeEnabled = + Boolean.parseBoolean( + environment.getProperty("stream-query.mybatis-plus.safe-mode", "false")); + } + + public static boolean isSafeModeEnabled() { + return safeModeEnabled; + } + /** * defaultSqlInjector. * diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java new file mode 100644 index 00000000..2342b3f2 --- /dev/null +++ b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java @@ -0,0 +1,64 @@ +/* + * 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.dromara.streamquery.stream.plugin.mybatisplus.engine.interceptor; + +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.StringValue; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.dromara.streamquery.stream.plugin.mybatisplus.engine.utils.SqlInjectionUtilSq; + +/** + * @author Cason + * @date 2023-06-23 21:36 + */ +public class SqTenantLineInnerInterceptor extends TenantLineInnerInterceptor { + public SqTenantLineInnerInterceptor(TenantLineHandler tenantLineHandler) { + super(tenantLineHandler); + } + + @Override + public void beforeQuery( + Executor executor, + MappedStatement ms, + Object parameter, + RowBounds rowBounds, + ResultHandler resultHandler, + BoundSql boundSql) { + if (!InterceptorIgnoreHelper.willIgnoreTenantLine(ms.getId())) { + Expression tenantId = this.getTenantLineHandler().getTenantId(); + if (tenantId instanceof StringValue) { + StringValue stringValue = (StringValue) tenantId; + String tenantIdStr = stringValue.getValue(); + if (SqlInjectionUtilSq.check(tenantIdStr)) { + throw new IllegalArgumentException( + "SQL Injection attempt detected in 'TenantLineInnerInterceptor'"); + } + } + PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); + String parsedSql = this.parserSingle(mpBs.sql(), null); + mpBs.sql(parsedSql); + } + } +} diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/utils/SqlInjectionUtilSq.java b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/utils/SqlInjectionUtilSq.java new file mode 100644 index 00000000..6922dd31 --- /dev/null +++ b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/utils/SqlInjectionUtilSq.java @@ -0,0 +1,45 @@ +/* + * 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.dromara.streamquery.stream.plugin.mybatisplus.engine.utils; + +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * @author Cason + * @since 2023-06-29 + */ +public class SqlInjectionUtilSq { + private static final Pattern SQL_SYNTAX_PATTERN = + Pattern.compile( + "(insert|delete|update|select|create|drop|truncate|grant|alter|deny|revoke|call|execute|exec|declare|show|rename|set)\\s+.*(into|from|set|where|table|database|view|index|on|cursor|procedure|trigger|for|password|union|and|or)|(select\\s*\\*\\s*from\\s+)", + Pattern.CASE_INSENSITIVE); + private static final Pattern SQL_COMMENT_PATTERN = + Pattern.compile("(or|union|--|#|/*|;)", Pattern.CASE_INSENSITIVE); + + public SqlInjectionUtilSq() {} + + public static boolean check(String value) { + Objects.requireNonNull(value); + return SQL_COMMENT_PATTERN.matcher(value).find() || SQL_SYNTAX_PATTERN.matcher(value).find(); + } + + public static String removeEscapeCharacter(String text) { + Objects.nonNull(text); + return text.replaceAll("\"", "").replaceAll("'", ""); + } +} diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/MybatisPlusTestApplication.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/MybatisPlusTestApplication.java index 89cccada..fff79ae2 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/MybatisPlusTestApplication.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/MybatisPlusTestApplication.java @@ -25,6 +25,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; * @author VampireAchao Cizai_ * @since 2022/5/21 */ -@SpringBootApplication @EnableMybatisPlusPlugin("org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po") +@SpringBootApplication public class MybatisPlusTestApplication {} diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductCategory.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductCategory.java new file mode 100644 index 00000000..12fe6d4f --- /dev/null +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductCategory.java @@ -0,0 +1,41 @@ +/* + * 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.dromara.streamquery.stream.plugin.mybatisplus.pojo.po; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import issue.org.dromara.streamquery.gitee.issue17BSNV.Table; +import lombok.Data; + +/** + * @author Cason + * @since 2023-06-27 + */ +@Data +@Table("product_category") +public class ProductCategory { + private static final long serialVersionUID = -7219188882388819210L; + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + private Long productId; + + private Long categoryId; + + private String tenantId; +} diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductInfo.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductInfo.java new file mode 100644 index 00000000..b5fce347 --- /dev/null +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductInfo.java @@ -0,0 +1,44 @@ +/* + * 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.dromara.streamquery.stream.plugin.mybatisplus.pojo.po; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import issue.org.dromara.streamquery.gitee.issue17BSNV.Table; +import lombok.Data; +import org.dromara.streamquery.stream.plugin.mybatisplus.engine.mapper.IGenerateMapper; + +import java.math.BigDecimal; + +/** + * @author Cason + * @since 2023-06-27 20:13 + */ +@Data +@Table("product_info") +public class ProductInfo implements IGenerateMapper { + private static final long serialVersionUID = -7219188882388819210L; + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + private String productName; + + private BigDecimal productPrice; + + private String tenantId; +} diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java new file mode 100644 index 00000000..ad7ac432 --- /dev/null +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java @@ -0,0 +1,91 @@ +/* + * 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.dromara.streamquery.stream.plugin.mybatisplus.safe; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTest; +import lombok.val; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.StringValue; +import org.apache.ibatis.exceptions.PersistenceException; +import org.dromara.streamquery.stream.plugin.mybatisplus.Database; +import org.dromara.streamquery.stream.plugin.mybatisplus.MybatisPlusTestApplication; +import org.dromara.streamquery.stream.plugin.mybatisplus.QueryCondition; +import org.dromara.streamquery.stream.plugin.mybatisplus.engine.interceptor.SqTenantLineInnerInterceptor; +import org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po.ProductInfo; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.ContextConfiguration; + +/** + * @author Cason + * @since 2023-06-27 + */ +@MybatisPlusTest +@ContextConfiguration( + classes = {MybatisPlusTestApplication.class, SqlInjectionTenantTest.TenantPluginConfig.class}) +public class SqlInjectionTenantTest { + static class TenantPluginConfig { + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor2() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); + interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); + interceptor.addInnerInterceptor( + new SqTenantLineInnerInterceptor( + new TenantLineHandler() { + @Override + public Expression getTenantId() { + return new StringValue("' or 1=1 and '123'='123"); + } + + @Override + public String getTenantIdColumn() { + return "tenant_id"; + } + + @Override + public boolean ignoreTable(String tableName) { + return "user_info".equalsIgnoreCase(tableName); + } + })); + return interceptor; + } + } + + @Test + void TenantTest() { + Throwable exception = + Assertions.assertThrows( + PersistenceException.class, + () -> { + QueryCondition wrapper = + QueryCondition.query(ProductInfo.class).eq(ProductInfo::getId, 1L); + val list = Database.list(wrapper); + }); + + Assertions.assertTrue(exception.getCause() instanceof IllegalArgumentException); + Assertions.assertEquals( + "SQL Injection attempt detected in 'TenantLineInnerInterceptor'", + exception.getCause().getMessage()); + } +} diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java new file mode 100644 index 00000000..de167a35 --- /dev/null +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java @@ -0,0 +1,64 @@ +/* + * 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.dromara.streamquery.stream.plugin.mybatisplus.safe; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTest; +import lombok.val; +import org.dromara.streamquery.stream.plugin.mybatisplus.Database; +import org.dromara.streamquery.stream.plugin.mybatisplus.QueryCondition; +import org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po.UserInfo; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author Cason + * @since 2023-06-27 + */ +@MybatisPlusTest +public class SqlInjectionWrapperTest { + + @Test + void applyTest() { + String unsafeSql = "'1 = 1) OR 1 = 1 --"; + Throwable exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> { + LambdaQueryWrapper wrapper = + QueryCondition.query(UserInfo.class).apply(unsafeSql); + val list = Database.list(wrapper); + }); + + Assertions.assertEquals("SQL Injection attempt detected in 'apply'", exception.getMessage()); + } + + @Test + void havingApply() { + String unsafeSql = "1 = 1) OR 1 = 1 --"; + Throwable exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> { + LambdaQueryWrapper wrapper = + QueryCondition.query(UserInfo.class).having(unsafeSql); + val list = Database.list(wrapper); + }); + + Assertions.assertEquals("SQL Injection attempt detected in 'having'", exception.getMessage()); + } +} diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/application.yml b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/application.yml index 6aa41812..c775fb96 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/application.yml +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/application.yml @@ -6,6 +6,7 @@ logging: stream-query: mybatis-plus: + safe-mode: on dynamic-mapper: base-packages: - org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/data.sql b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/data.sql index b8cf986e..98dfebce 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/data.sql +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/data.sql @@ -30,3 +30,26 @@ INSERT INTO role_info (id, role_name) VALUES ('1', 'admin'), ('2', 'user'), ('3', 'guest'); + +DELETE FROM product_info; + +INSERT INTO product_info (product_name, product_price, tenant_id) +VALUES ('Apple iPhone 13', 699, '1'), + ('Samsung Galaxy S21', 799, '1'), + ('OnePlus 9 Pro', 969, '1'), + ('Google Pixel 6', 599, '2'), + ('Sony Xperia 1 III', 1199, '1'); + +DELETE FROM product_category; + +INSERT INTO product_category (product_id, category_id, tenant_id) +VALUES (1, 1, '1'), + (1, 2, '1'), + (2, 1, '1'), + (2, 3, '1'), + (3, 1, '1'), + (4, 1, '2'), + (4, 2, '2'), + (5, 1, '1'), + (5, 2, '1'), + (5, 3, '1'); diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/schema.sql b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/schema.sql index 3ab26d11..58b89d73 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/schema.sql +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/schema.sql @@ -25,4 +25,24 @@ create table if not exists role_info id VARCHAR(30) NOT NULL, role_name VARCHAR(30) DEFAULT NULL, PRIMARY KEY (id) -); \ No newline at end of file +); + +drop table if exists product_info; +create table if not exists product_info +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + product_name VARCHAR(50) DEFAULT NULL, + product_price FLOAT DEFAULT NULL, + tenant_id VARCHAR(50) DEFAULT NULL, + PRIMARY KEY (id) + ); + +drop table if exists product_category; +create table if not exists product_category +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + product_id BIGINT DEFAULT NULL, + category_id BIGINT DEFAULT NULL, + tenant_id VARCHAR(50) DEFAULT NULL, + PRIMARY KEY (id) + ); \ No newline at end of file -- Gitee From 4bc743a5605228975823692cd8623b163833927f Mon Sep 17 00:00:00 2001 From: Cason <1125193113@qq.com> Date: Thu, 29 Jun 2023 21:43:11 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatisplus/safe/SqlInjectionTenantTest.java | 8 ++++---- .../mybatisplus/safe/SqlInjectionWrapperTest.java | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java index ad7ac432..eabed8d8 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java @@ -43,7 +43,7 @@ import org.springframework.test.context.ContextConfiguration; @MybatisPlusTest @ContextConfiguration( classes = {MybatisPlusTestApplication.class, SqlInjectionTenantTest.TenantPluginConfig.class}) -public class SqlInjectionTenantTest { +class SqlInjectionTenantTest { static class TenantPluginConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor2() { @@ -74,13 +74,13 @@ public class SqlInjectionTenantTest { @Test void TenantTest() { + QueryCondition wrapper = + QueryCondition.query(ProductInfo.class).eq(ProductInfo::getId, 1L); Throwable exception = Assertions.assertThrows( PersistenceException.class, () -> { - QueryCondition wrapper = - QueryCondition.query(ProductInfo.class).eq(ProductInfo::getId, 1L); - val list = Database.list(wrapper); + Database.list(wrapper); }); Assertions.assertTrue(exception.getCause() instanceof IllegalArgumentException); diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java index de167a35..5361e18d 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java @@ -30,18 +30,18 @@ import org.junit.jupiter.api.Test; * @since 2023-06-27 */ @MybatisPlusTest -public class SqlInjectionWrapperTest { +class SqlInjectionWrapperTest { @Test void applyTest() { String unsafeSql = "'1 = 1) OR 1 = 1 --"; + LambdaQueryWrapper wrapper = + QueryCondition.query(UserInfo.class).apply(unsafeSql); + val list = Database.list(wrapper); Throwable exception = Assertions.assertThrows( IllegalArgumentException.class, () -> { - LambdaQueryWrapper wrapper = - QueryCondition.query(UserInfo.class).apply(unsafeSql); - val list = Database.list(wrapper); }); Assertions.assertEquals("SQL Injection attempt detected in 'apply'", exception.getMessage()); @@ -50,12 +50,12 @@ public class SqlInjectionWrapperTest { @Test void havingApply() { String unsafeSql = "1 = 1) OR 1 = 1 --"; + LambdaQueryWrapper wrapper = + QueryCondition.query(UserInfo.class).having(unsafeSql); Throwable exception = Assertions.assertThrows( IllegalArgumentException.class, () -> { - LambdaQueryWrapper wrapper = - QueryCondition.query(UserInfo.class).having(unsafeSql); val list = Database.list(wrapper); }); -- Gitee From 1806fc4f7f19898c3d6b3f7415862f85eeb19963 Mon Sep 17 00:00:00 2001 From: Cason <1125193113@qq.com> Date: Sun, 2 Jul 2023 15:10:33 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=A7=9F=E6=88=B7?= =?UTF-8?q?=E6=8F=92=E4=BB=B6sql=E6=B3=A8=E5=85=A5=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E5=BC=8F=EF=BC=8C=E5=AE=8C=E5=96=84=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SqTenantLineInnerInterceptor.java | 50 +++++++++---------- .../plugin/mybatisplus/DatabaseTest.java | 1 + .../mybatisplus/JsonFieldHandlerTest.java | 4 ++ .../plugin/mybatisplus/WrapperHelperTest.java | 1 + .../safe/SqlInjectionTenantTest.java | 30 ++++++++++- 5 files changed, 58 insertions(+), 28 deletions(-) diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java index fbeb8b3c..572b5c5b 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java @@ -16,19 +16,17 @@ */ package org.dromara.streamquery.stream.plugin.mybatisplus.engine.interceptor; -import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; -import com.baomidou.mybatisplus.core.toolkit.PluginUtils; + import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.StringValue; -import org.apache.ibatis.executor.Executor; -import org.apache.ibatis.mapping.BoundSql; -import org.apache.ibatis.mapping.MappedStatement; -import org.apache.ibatis.session.ResultHandler; -import org.apache.ibatis.session.RowBounds; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.insert.Insert; import org.dromara.streamquery.stream.plugin.mybatisplus.engine.utils.SqlInjectionUtilSq; + + /** * @author Cason * @since 2023-06-23 21:36 @@ -39,26 +37,26 @@ public class SqTenantLineInnerInterceptor extends TenantLineInnerInterceptor { } @Override - public void beforeQuery( - Executor executor, - MappedStatement ms, - Object parameter, - RowBounds rowBounds, - ResultHandler resultHandler, - BoundSql boundSql) { - if (!InterceptorIgnoreHelper.willIgnoreTenantLine(ms.getId())) { - Expression tenantId = this.getTenantLineHandler().getTenantId(); - if (tenantId instanceof StringValue) { - StringValue stringValue = (StringValue) tenantId; - String tenantIdStr = stringValue.getValue(); - if (SqlInjectionUtilSq.check(tenantIdStr)) { - throw new IllegalArgumentException( - "SQL Injection attempt detected in 'TenantLineInnerInterceptor'"); - } + protected void processInsert(Insert insert, int index, String sql, Object obj) { + checkTenantId(); + super.processInsert(insert, index, sql, obj); + } + + @Override + public Expression buildTableExpression(Table table, Expression where, String whereSegment) { + checkTenantId(); + return super.buildTableExpression(table, where, whereSegment); + } + + private void checkTenantId() { + Expression tenantId = this.getTenantLineHandler().getTenantId(); + if (tenantId instanceof StringValue) { + StringValue stringValue = (StringValue) tenantId; + String tenantIdStr = stringValue.getValue(); + if (SqlInjectionUtilSq.check(tenantIdStr)) { + throw new IllegalArgumentException( + "SQL Injection attempt detected in 'TenantLineInnerInterceptor'"); } - PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); - String parsedSql = this.parserSingle(mpBs.sql(), null); - mpBs.sql(parsedSql); } } } diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/DatabaseTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/DatabaseTest.java index 9a6847cb..74ab3602 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/DatabaseTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/DatabaseTest.java @@ -43,6 +43,7 @@ import org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po.UserInfo; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Bean; +import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; import java.lang.reflect.Proxy; diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java index 3071412f..769b7107 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java @@ -30,10 +30,12 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.dromara.streamquery.stream.core.collection.Lists; import org.dromara.streamquery.stream.core.lambda.function.SerSupp; import org.dromara.streamquery.stream.plugin.mybatisplus.engine.handler.AbstractJsonFieldHandler; +import org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po.UserInfo; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; import java.io.Serializable; import java.util.List; @@ -70,6 +72,8 @@ class JsonFieldHandlerTest { Database.saveFewSql(Lists.of(user)); Database.updateFewSql(Lists.of(user)); val dbUser = Database.getById(user.getId(), UserInfoWithJsonName.class); +// val user1 = Database.list(new LambdaQueryWrapper<>(UserInfoWithJsonName.class).eq(UserInfoWithJsonName::getName, user.getName())); + Database.updateById(user); Assertions.assertEquals("VampireAchao", dbUser.getName().getUsername()); Assertions.assertEquals("阿超", dbUser.getName().getNickname()); } diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/WrapperHelperTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/WrapperHelperTest.java index 51ff4453..a221688c 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/WrapperHelperTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/WrapperHelperTest.java @@ -25,6 +25,7 @@ import org.dromara.streamquery.stream.core.collection.Lists; import org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po.UserInfo; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.springframework.test.annotation.DirtiesContext; import java.util.List; import java.util.Objects; diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java index 07705bd1..17a351b1 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java @@ -65,15 +65,41 @@ class SqlInjectionTenantTest { } @Test - void TenantTest() { + void queryTest() { QueryCondition wrapper = QueryCondition.query(ProductInfo.class).eq(ProductInfo::getId, 1L); Throwable exception = Assertions.assertThrows(PersistenceException.class, () -> Database.list(wrapper)); - Assertions.assertTrue(exception.getCause() instanceof IllegalArgumentException); Assertions.assertEquals( "SQL Injection attempt detected in 'TenantLineInnerInterceptor'", exception.getCause().getMessage()); } + + @Test + void insertTest() { + ProductInfo product = new ProductInfo(); + product.setId(2L); + product.setProductName("Product 2"); + Throwable exception = Assertions.assertThrows(PersistenceException.class, () -> Database.save(product)); + Assertions.assertTrue(exception.getCause() instanceof IllegalArgumentException); + Assertions.assertEquals( + "SQL Injection attempt detected in 'TenantLineInnerInterceptor'", + exception.getCause().getMessage()); + } + + @Test + void updateTest() { + ProductInfo product = new ProductInfo(); + product.setId(1L); + product.setProductName("Updated Product 1"); + Throwable exception = Assertions.assertThrows(PersistenceException.class, () -> Database.updateById(product)); + Assertions.assertTrue(exception.getCause() instanceof IllegalArgumentException); + Assertions.assertEquals( + "SQL Injection attempt detected in 'TenantLineInnerInterceptor'", + exception.getCause().getMessage()); + } + + + } -- Gitee From 23965cca7a79ae20c0209ee4dd98f89a92947aa8 Mon Sep 17 00:00:00 2001 From: Cason <1125193113@qq.com> Date: Sun, 2 Jul 2023 15:35:45 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=A7=9F=E6=88=B7?= =?UTF-8?q?=E6=8F=92=E4=BB=B6sql=E6=B3=A8=E5=85=A5=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E5=BC=8F=EF=BC=8C=E5=AE=8C=E5=96=84=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9apply=E5=92=8Chaving=E6=96=B9=E6=B3=95=E7=9A=84?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E6=96=B9=E5=BC=8F=EF=BC=8C=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=E7=9A=84?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stream/core/bean/BeanHelper.java | 4 +- .../plugin/mybatisplus/QueryCondition.java | 18 +++++++ .../StreamPluginAutoConfiguration.java | 15 ++++++ .../SqTenantLineInnerInterceptor.java | 3 -- .../engine/utils/SqlInjectionUtilSq.java | 45 ++++++++++++++++ .../plugin/mybatisplus/DatabaseTest.java | 1 - .../mybatisplus/JsonFieldHandlerTest.java | 6 +-- .../plugin/mybatisplus/WrapperHelperTest.java | 1 - .../mybatisplus/pojo/po/ProductCategory.java | 2 +- .../mybatisplus/pojo/po/ProductInfo.java | 44 +++++++++++++++ .../safe/SqlInjectionTenantTest.java | 49 +++++++++-------- .../safe/SqlInjectionWrapperTest.java | 53 +++++++++++++++++++ .../src/test/resources/application.yml | 1 + .../src/test/resources/data.sql | 23 ++++++++ .../src/test/resources/schema.sql | 22 +++++++- 15 files changed, 250 insertions(+), 37 deletions(-) create mode 100644 stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/utils/SqlInjectionUtilSq.java create mode 100644 stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductInfo.java create mode 100644 stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java diff --git a/stream-core/src/main/java/org/dromara/streamquery/stream/core/bean/BeanHelper.java b/stream-core/src/main/java/org/dromara/streamquery/stream/core/bean/BeanHelper.java index 5c6679c5..5f35f0c0 100644 --- a/stream-core/src/main/java/org/dromara/streamquery/stream/core/bean/BeanHelper.java +++ b/stream-core/src/main/java/org/dromara/streamquery/stream/core/bean/BeanHelper.java @@ -153,8 +153,8 @@ public class BeanHelper { LambdaExecutable targetGetterLambda = LambdaHelper.resolve(targetGetter); if (!Opp.of(sourceGetterLambda.getReturnType()) - .map(Type::getTypeName) - .equals(Opp.of(targetGetterLambda.getReturnType()).map(Type::getTypeName))) { + .map(Type::getTypeName) + .equals(Opp.of(targetGetterLambda.getReturnType()).map(Type::getTypeName))) { continue; } diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java index 92d07e69..7b5da81a 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java @@ -32,6 +32,8 @@ import org.dromara.streamquery.stream.core.lambda.LambdaExecutable; import org.dromara.streamquery.stream.core.lambda.LambdaHelper; import org.dromara.streamquery.stream.core.optional.Opp; import org.dromara.streamquery.stream.core.stream.Steam; +import org.dromara.streamquery.stream.plugin.mybatisplus.engine.configuration.StreamPluginAutoConfiguration; +import org.dromara.streamquery.stream.plugin.mybatisplus.engine.utils.SqlInjectionUtilSq; import java.util.Collection; import java.util.Map; @@ -266,4 +268,20 @@ public class QueryCondition extends LambdaQueryWrapper { SharedString.emptyString(), SharedString.emptyString()); } + + @Override + public LambdaQueryWrapper apply(boolean condition, String applySql, Object... values) { + if (StreamPluginAutoConfiguration.isSafeModeEnabled() && SqlInjectionUtilSq.check(applySql)) { + throw new IllegalArgumentException("SQL Injection attempt detected in 'apply'"); + } + return super.apply(condition, applySql, values); + } + + @Override + public LambdaQueryWrapper having(boolean condition, String sqlHaving, Object... params) { + if (StreamPluginAutoConfiguration.isSafeModeEnabled() && SqlInjectionUtilSq.check(sqlHaving)) { + throw new IllegalArgumentException("SQL Injection attempt detected in 'having'"); + } + return super.having(condition, sqlHaving, params); + } } diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/configuration/StreamPluginAutoConfiguration.java b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/configuration/StreamPluginAutoConfiguration.java index 00e43462..525d9831 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/configuration/StreamPluginAutoConfiguration.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/configuration/StreamPluginAutoConfiguration.java @@ -31,9 +31,11 @@ import org.dromara.streamquery.stream.plugin.mybatisplus.engine.handler.JsonPost import org.dromara.streamquery.stream.plugin.mybatisplus.engine.mapper.DynamicMapperHandler; import org.dromara.streamquery.stream.plugin.mybatisplus.engine.methods.SaveOneSql; import org.dromara.streamquery.stream.plugin.mybatisplus.engine.methods.UpdateOneSql; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.core.annotation.Order; +import org.springframework.core.env.Environment; import java.util.List; @@ -47,6 +49,19 @@ public class StreamPluginAutoConfiguration { private static final String CURRENT_NAMESPACE = LambdaHelper.getPropertyName(TableInfo::getCurrentNamespace); + private static boolean safeModeEnabled; + + @Autowired + public void setEnvironment(Environment environment) { + safeModeEnabled = + Boolean.parseBoolean( + environment.getProperty("stream-query.mybatis-plus.safe-mode", "false")); + } + + public static boolean isSafeModeEnabled() { + return safeModeEnabled; + } + /** * defaultSqlInjector. * diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java index 572b5c5b..8faa139f 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/interceptor/SqTenantLineInnerInterceptor.java @@ -16,7 +16,6 @@ */ package org.dromara.streamquery.stream.plugin.mybatisplus.engine.interceptor; - import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; import net.sf.jsqlparser.expression.Expression; @@ -25,8 +24,6 @@ import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.insert.Insert; import org.dromara.streamquery.stream.plugin.mybatisplus.engine.utils.SqlInjectionUtilSq; - - /** * @author Cason * @since 2023-06-23 21:36 diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/utils/SqlInjectionUtilSq.java b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/utils/SqlInjectionUtilSq.java new file mode 100644 index 00000000..6922dd31 --- /dev/null +++ b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/engine/utils/SqlInjectionUtilSq.java @@ -0,0 +1,45 @@ +/* + * 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.dromara.streamquery.stream.plugin.mybatisplus.engine.utils; + +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * @author Cason + * @since 2023-06-29 + */ +public class SqlInjectionUtilSq { + private static final Pattern SQL_SYNTAX_PATTERN = + Pattern.compile( + "(insert|delete|update|select|create|drop|truncate|grant|alter|deny|revoke|call|execute|exec|declare|show|rename|set)\\s+.*(into|from|set|where|table|database|view|index|on|cursor|procedure|trigger|for|password|union|and|or)|(select\\s*\\*\\s*from\\s+)", + Pattern.CASE_INSENSITIVE); + private static final Pattern SQL_COMMENT_PATTERN = + Pattern.compile("(or|union|--|#|/*|;)", Pattern.CASE_INSENSITIVE); + + public SqlInjectionUtilSq() {} + + public static boolean check(String value) { + Objects.requireNonNull(value); + return SQL_COMMENT_PATTERN.matcher(value).find() || SQL_SYNTAX_PATTERN.matcher(value).find(); + } + + public static String removeEscapeCharacter(String text) { + Objects.nonNull(text); + return text.replaceAll("\"", "").replaceAll("'", ""); + } +} diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/DatabaseTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/DatabaseTest.java index 74ab3602..9a6847cb 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/DatabaseTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/DatabaseTest.java @@ -43,7 +43,6 @@ import org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po.UserInfo; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Bean; -import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; import java.lang.reflect.Proxy; diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java index 769b7107..32bbf7e3 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java @@ -30,12 +30,10 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.dromara.streamquery.stream.core.collection.Lists; import org.dromara.streamquery.stream.core.lambda.function.SerSupp; import org.dromara.streamquery.stream.plugin.mybatisplus.engine.handler.AbstractJsonFieldHandler; -import org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po.UserInfo; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.annotation.DirtiesContext; import java.io.Serializable; import java.util.List; @@ -72,7 +70,9 @@ class JsonFieldHandlerTest { Database.saveFewSql(Lists.of(user)); Database.updateFewSql(Lists.of(user)); val dbUser = Database.getById(user.getId(), UserInfoWithJsonName.class); -// val user1 = Database.list(new LambdaQueryWrapper<>(UserInfoWithJsonName.class).eq(UserInfoWithJsonName::getName, user.getName())); + // val user1 = Database.list(new + // LambdaQueryWrapper<>(UserInfoWithJsonName.class).eq(UserInfoWithJsonName::getName, + // user.getName())); Database.updateById(user); Assertions.assertEquals("VampireAchao", dbUser.getName().getUsername()); Assertions.assertEquals("阿超", dbUser.getName().getNickname()); diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/WrapperHelperTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/WrapperHelperTest.java index a221688c..51ff4453 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/WrapperHelperTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/WrapperHelperTest.java @@ -25,7 +25,6 @@ import org.dromara.streamquery.stream.core.collection.Lists; import org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po.UserInfo; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.springframework.test.annotation.DirtiesContext; import java.util.List; import java.util.Objects; diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductCategory.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductCategory.java index 12fe6d4f..fd4fe7a3 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductCategory.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductCategory.java @@ -18,8 +18,8 @@ package org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; -import issue.org.dromara.streamquery.gitee.issue17BSNV.Table; import lombok.Data; +import org.dromara.streamquery.stream.plugin.mybatisplus.issue.gitee.issue17BSNV.Table; /** * @author Cason diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductInfo.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductInfo.java new file mode 100644 index 00000000..f0ab2f89 --- /dev/null +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/pojo/po/ProductInfo.java @@ -0,0 +1,44 @@ +/* + * 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.dromara.streamquery.stream.plugin.mybatisplus.pojo.po; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import org.dromara.streamquery.stream.plugin.mybatisplus.engine.mapper.IGenerateMapper; +import org.dromara.streamquery.stream.plugin.mybatisplus.issue.gitee.issue17BSNV.Table; + +import java.math.BigDecimal; + +/** + * @author Cason + * @since 2023-06-27 20:13 + */ +@Data +@Table("product_info") +public class ProductInfo implements IGenerateMapper { + private static final long serialVersionUID = -7219188882388819210L; + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + private String productName; + + private BigDecimal productPrice; + + private String tenantId; +} diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java index 17a351b1..3dc7ea13 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionTenantTest.java @@ -76,30 +76,29 @@ class SqlInjectionTenantTest { exception.getCause().getMessage()); } - @Test - void insertTest() { - ProductInfo product = new ProductInfo(); - product.setId(2L); - product.setProductName("Product 2"); - Throwable exception = Assertions.assertThrows(PersistenceException.class, () -> Database.save(product)); - Assertions.assertTrue(exception.getCause() instanceof IllegalArgumentException); - Assertions.assertEquals( - "SQL Injection attempt detected in 'TenantLineInnerInterceptor'", - exception.getCause().getMessage()); - } - - @Test - void updateTest() { - ProductInfo product = new ProductInfo(); - product.setId(1L); - product.setProductName("Updated Product 1"); - Throwable exception = Assertions.assertThrows(PersistenceException.class, () -> Database.updateById(product)); - Assertions.assertTrue(exception.getCause() instanceof IllegalArgumentException); - Assertions.assertEquals( - "SQL Injection attempt detected in 'TenantLineInnerInterceptor'", - exception.getCause().getMessage()); - } - - + @Test + void insertTest() { + ProductInfo product = new ProductInfo(); + product.setId(2L); + product.setProductName("Product 2"); + Throwable exception = + Assertions.assertThrows(PersistenceException.class, () -> Database.save(product)); + Assertions.assertTrue(exception.getCause() instanceof IllegalArgumentException); + Assertions.assertEquals( + "SQL Injection attempt detected in 'TenantLineInnerInterceptor'", + exception.getCause().getMessage()); + } + @Test + void updateTest() { + ProductInfo product = new ProductInfo(); + product.setId(1L); + product.setProductName("Updated Product 1"); + Throwable exception = + Assertions.assertThrows(PersistenceException.class, () -> Database.updateById(product)); + Assertions.assertTrue(exception.getCause() instanceof IllegalArgumentException); + Assertions.assertEquals( + "SQL Injection attempt detected in 'TenantLineInnerInterceptor'", + exception.getCause().getMessage()); + } } diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java new file mode 100644 index 00000000..c320d618 --- /dev/null +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/safe/SqlInjectionWrapperTest.java @@ -0,0 +1,53 @@ +/* + * 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.dromara.streamquery.stream.plugin.mybatisplus.safe; + +import com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTest; +import org.dromara.streamquery.stream.plugin.mybatisplus.QueryCondition; +import org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po.UserInfo; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author Cason + * @since 2023-06-27 + */ +@MybatisPlusTest +class SqlInjectionWrapperTest { + + @Test + void applyTest() { + String unsafeSql = "1 = 1) OR 1 = 1 --"; + Throwable exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> QueryCondition.query(UserInfo.class).apply(unsafeSql)); + + Assertions.assertEquals("SQL Injection attempt detected in 'apply'", exception.getMessage()); + } + + @Test + void havingApply() { + String unsafeSql = "1 = 1) OR 1 = 1 --"; + Throwable exception = + Assertions.assertThrows( + IllegalArgumentException.class, + () -> QueryCondition.query(UserInfo.class).having(unsafeSql)); + + Assertions.assertEquals("SQL Injection attempt detected in 'having'", exception.getMessage()); + } +} diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/application.yml b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/application.yml index 6aa41812..c775fb96 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/application.yml +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/application.yml @@ -6,6 +6,7 @@ logging: stream-query: mybatis-plus: + safe-mode: on dynamic-mapper: base-packages: - org.dromara.streamquery.stream.plugin.mybatisplus.pojo.po diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/data.sql b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/data.sql index b8cf986e..427d0ed4 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/data.sql +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/data.sql @@ -30,3 +30,26 @@ INSERT INTO role_info (id, role_name) VALUES ('1', 'admin'), ('2', 'user'), ('3', 'guest'); + +DELETE FROM product_info; + +INSERT INTO product_info (product_name, product_price, tenant_id) +VALUES ('Apple iPhone 13', 699, '1'), + ('Samsung Galaxy S21', 799, '1'), + ('OnePlus 9 Pro', 969, '1'), + ('Google Pixel 6', 599, '2'), + ('Sony Xperia 1 III', 1199, '1'); + +DELETE FROM product_category; + +INSERT INTO product_category (product_id, category_id, tenant_id) +VALUES (1, 1, '1'), + (1, 2, '1'), + (2, 1, '1'), + (2, 3, '1'), + (3, 1, '1'), + (4, 1, '2'), + (4, 2, '2'), + (5, 1, '1'), + (5, 2, '1'), + (5, 3, '1'); \ No newline at end of file diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/schema.sql b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/schema.sql index 3ab26d11..58b89d73 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/schema.sql +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/resources/schema.sql @@ -25,4 +25,24 @@ create table if not exists role_info id VARCHAR(30) NOT NULL, role_name VARCHAR(30) DEFAULT NULL, PRIMARY KEY (id) -); \ No newline at end of file +); + +drop table if exists product_info; +create table if not exists product_info +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + product_name VARCHAR(50) DEFAULT NULL, + product_price FLOAT DEFAULT NULL, + tenant_id VARCHAR(50) DEFAULT NULL, + PRIMARY KEY (id) + ); + +drop table if exists product_category; +create table if not exists product_category +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, + product_id BIGINT DEFAULT NULL, + category_id BIGINT DEFAULT NULL, + tenant_id VARCHAR(50) DEFAULT NULL, + PRIMARY KEY (id) + ); \ No newline at end of file -- Gitee From 6a9dd9054be61194f470fb345e8237175f13823b Mon Sep 17 00:00:00 2001 From: Cason <1125193113@qq.com> Date: Sun, 2 Jul 2023 17:17:54 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E5=8F=96=E5=87=BA=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E6=97=A0=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stream/plugin/mybatisplus/JsonFieldHandlerTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java index 32bbf7e3..3071412f 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java @@ -70,10 +70,6 @@ class JsonFieldHandlerTest { Database.saveFewSql(Lists.of(user)); Database.updateFewSql(Lists.of(user)); val dbUser = Database.getById(user.getId(), UserInfoWithJsonName.class); - // val user1 = Database.list(new - // LambdaQueryWrapper<>(UserInfoWithJsonName.class).eq(UserInfoWithJsonName::getName, - // user.getName())); - Database.updateById(user); Assertions.assertEquals("VampireAchao", dbUser.getName().getUsername()); Assertions.assertEquals("阿超", dbUser.getName().getNickname()); } -- Gitee From 554834853773a1a821bea8cc0adf264c75f92cde Mon Sep 17 00:00:00 2001 From: Cason <1125193113@qq.com> Date: Tue, 4 Jul 2023 21:06:59 +0800 Subject: [PATCH 6/7] =?UTF-8?q?QueryCondition=E9=87=8D=E5=86=99=E4=B8=80?= =?UTF-8?q?=E4=B8=8Bor=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stream/plugin/mybatisplus/QueryCondition.java | 6 ++++++ .../stream/plugin/mybatisplus/JsonFieldHandlerTest.java | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java index 7b5da81a..1ab2ecda 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java @@ -206,6 +206,12 @@ public class QueryCondition extends LambdaQueryWrapper { return this; } + @Override + public QueryCondition or(Consumer> consumer) { + super.or(consumer); + return this; + } + @Override protected LambdaQueryWrapper addCondition( boolean condition, SFunction column, SqlKeyword sqlKeyword, Object val) { diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java index 3071412f..3f96b90e 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java @@ -144,10 +144,9 @@ class JsonFieldHandlerTest { Database.saveFewSql(Lists.of(user1, user2, user3)); QueryCondition wrapper = - (QueryCondition) QueryCondition.query(UserInfoWithJsonName.class) - .in(UserInfoWithJsonName::getName, Lists.of(name1, name3)) - .or(i -> i.eq(UserInfoWithJsonName::getName, user2.getName())); + .in(UserInfoWithJsonName::getName, Lists.of(name1, name3)) + .or(i -> i.eq(UserInfoWithJsonName::getName, user2.getName())); val list = Database.list(wrapper); -- Gitee From 83ea9e66a25be5a6f9d26b85cc4bc726c1b96088 Mon Sep 17 00:00:00 2001 From: Cason <1125193113@qq.com> Date: Wed, 5 Jul 2023 21:17:59 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9QueryCondition=E7=9A=84?= =?UTF-8?q?=E9=83=A8=E5=88=86=E6=96=B9=E6=B3=95=EF=BC=8C=E5=BA=9F=E5=BC=83?= =?UTF-8?q?=E9=83=A8=E5=88=86=E6=96=B9=E6=B3=95=E3=80=82=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9Eand=E5=92=8C=E5=AF=B9=E5=BA=94=E7=9A=84=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95=20=E9=87=8D=E6=96=B0=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E4=BA=86=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E5=AE=9E=E4=BD=93=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/mybatisplus/QueryCondition.java | 31 ++++++++++--- .../mybatisplus/JsonFieldHandlerTest.java | 43 ++++++++++++++++--- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java index 1ab2ecda..f3ba9061 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/main/java/org/dromara/streamquery/stream/plugin/mybatisplus/QueryCondition.java @@ -37,7 +37,6 @@ import org.dromara.streamquery.stream.plugin.mybatisplus.engine.utils.SqlInjecti import java.util.Collection; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -107,7 +106,9 @@ public class QueryCondition extends LambdaQueryWrapper { * @param column a {@link SFunction} object * @param data a {@link String} object * @return a {@link QueryCondition} object + * @deprecated because this method is superfluous */ + @Deprecated public QueryCondition eq(SFunction column, String data) { super.eq(StringUtils.isNotEmpty(data), column, data); return this; @@ -121,8 +122,8 @@ public class QueryCondition extends LambdaQueryWrapper { * @param a R class * @return a {@link QueryCondition} object */ - public > QueryCondition eq(SFunction column, R data) { - super.eq(Objects.nonNull(data), column, data); + public QueryCondition eq(SFunction column, R data) { + super.eq(column, data); return this; } @@ -132,7 +133,9 @@ public class QueryCondition extends LambdaQueryWrapper { * @param column a {@link SFunction} object * @param data a {@link String} object * @return a {@link QueryCondition} object + * @deprecated because this method is superfluous */ + @Deprecated public QueryCondition like(SFunction column, String data) { super.like(StringUtils.isNotEmpty(data), column, data); return this; @@ -146,10 +149,10 @@ public class QueryCondition extends LambdaQueryWrapper { * @param a R class * @return a {@link QueryCondition} object */ - public > QueryCondition in( + public QueryCondition in( SFunction column, Collection dataList) { this.mapping = getMapping(column); - super.in(CollectionUtils.isNotEmpty(dataList), column, dataList); + super.in(column, dataList); return this; } @@ -159,7 +162,9 @@ public class QueryCondition extends LambdaQueryWrapper { * @param column a {@link SFunction} object * @param data a {@link String} object * @return a {@link QueryCondition} object + * @deprecated because this method is superfluous */ + @Deprecated public QueryCondition activeEq(SFunction column, String data) { Opp.of(data).map(v -> super.eq(column, v)).orElseRun(() -> Database.notActive(this)); return this; @@ -172,8 +177,10 @@ public class QueryCondition extends LambdaQueryWrapper { * @param data a R object * @param a R class * @return a {@link QueryCondition} object + * @deprecated because this method is optional */ - public > QueryCondition activeEq( + @Deprecated + public QueryCondition activeEq( SFunction column, R data) { Opp.of(data).map(v -> super.eq(column, v)).orElseRun(() -> Database.notActive(this)); return this; @@ -185,7 +192,9 @@ public class QueryCondition extends LambdaQueryWrapper { * @param column a {@link SFunction} object * @param data a {@link String} object * @return a {@link QueryCondition} object + * @deprecated because this method is superfluous */ + @Deprecated public QueryCondition activeLike(SFunction column, String data) { Opp.of(data).map(v -> super.like(column, v)).orElseRun(() -> Database.notActive(this)); return this; @@ -198,8 +207,10 @@ public class QueryCondition extends LambdaQueryWrapper { * @param dataList a {@link Collection} object * @param a R class * @return a {@link QueryCondition} object + * @deprecated because this method is optional */ - public > QueryCondition activeIn( + @Deprecated + public QueryCondition activeIn( SFunction column, Collection dataList) { this.mapping = getMapping(column); Opp.ofColl(dataList).map(v -> super.in(column, v)).orElseRun(() -> Database.notActive(this)); @@ -212,6 +223,12 @@ public class QueryCondition extends LambdaQueryWrapper { return this; } + @Override + public QueryCondition and(Consumer> consumer) { + super.and(consumer); + return this; + } + @Override protected LambdaQueryWrapper addCondition( boolean condition, SFunction column, SqlKeyword sqlKeyword, Object val) { diff --git a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java index 3f96b90e..3d828b56 100644 --- a/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java +++ b/stream-plugin/stream-plugin-mybatis-plus/src/test/java/org/dromara/streamquery/stream/plugin/mybatisplus/JsonFieldHandlerTest.java @@ -166,6 +166,42 @@ class JsonFieldHandlerTest { "Returned users should not contain the second username"); } + @Test + void andTest() { + Name name1 = new Name(); + name1.setUsername("Cason"); + name1.setNickname("JAY"); + + Name name2 = new Name(); + name2.setUsername("Alice"); + name2.setNickname("AL"); + + Name name3 = new Name(); + name3.setUsername("Bob"); + name3.setNickname("BB"); + + UserInfoWithJsonName user1 = new UserInfoWithJsonName(); + user1.setName(name1); + + UserInfoWithJsonName user2 = new UserInfoWithJsonName(); + user2.setName(name2); + + UserInfoWithJsonName user3 = new UserInfoWithJsonName(); + user3.setName(name3); + + Database.saveFewSql(Lists.of(user1, user2, user3)); + + QueryCondition wrapper = + QueryCondition.query(UserInfoWithJsonName.class) + .eq(UserInfoWithJsonName::getId, 1L) + .and(i -> i.eq(UserInfoWithJsonName::getName, user2.getName())); + + val list = Database.list(wrapper); + + assertEquals(0, list.size(), "Query should return exactly zero result"); + + } + @Test void InTest() { Name name1 = new Name(); @@ -312,13 +348,8 @@ class JsonFieldHandlerTest { } @Data - static class Name implements Serializable, Comparable { + static class Name implements Serializable { private String username; private String nickname; - - @Override - public int compareTo(Name o) { - return username.compareTo(o.username); - } } } -- Gitee