so that Hive UDF can be reused when desensitizing Flink SQL data. 68 | * 69 | *
Note: 70 | *
Note: Depending on the external Mysql environment, you can run it manually. 31 | * 32 | * @author: HamaWhite 33 | */ 34 | @Ignore 35 | public class ExecuteDataMaskTest extends AbstractBasicTest { 36 | 37 | @BeforeClass 38 | public static void init() { 39 | // create mysql cdc table orders 40 | createTableOfOrders(); 41 | 42 | // create print sink table print_sink 43 | createTableOfPrintSink(); 44 | 45 | // add data mask policies 46 | policyManager.addPolicy(dataMaskPolicy(USER_A, TABLE_ORDERS, "customer_name", "MASK")); 47 | policyManager.addPolicy(dataMaskPolicy(USER_B, TABLE_ORDERS, "customer_name", "MASK_SHOW_FIRST_4")); 48 | } 49 | 50 | /** 51 | * Execute without data mask 52 | */ 53 | @Test 54 | public void testExecute() { 55 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 56 | 57 | Object[][] expected = { 58 | {10001, "Jack", 102, "beijing"}, 59 | {10002, "Sally", 105, "beijing"}, 60 | {10003, "Edward", 106, "hangzhou"}, 61 | {10004, "John", 103, "hangzhou"}, 62 | {10005, "Edward", 104, "shanghai"}, 63 | {10006, "Jack", 103, "shanghai"} 64 | }; 65 | execute(sql, expected); 66 | } 67 | 68 | /** 69 | * User A view the customer_name after mask 70 | */ 71 | @Test 72 | public void testExecuteByUserA() { 73 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 74 | 75 | Object[][] expected = { 76 | {10001, "Xxxx", 102, "beijing"}, 77 | {10002, "Xxxxx", 105, "beijing"}, 78 | {10003, "Xxxxxx", 106, "hangzhou"}, 79 | {10004, "Xxxx", 103, "hangzhou"}, 80 | {10005, "Xxxxxx", 104, "shanghai"}, 81 | {10006, "Xxxx", 103, "shanghai"} 82 | }; 83 | executeDataMask(USER_A, sql, expected); 84 | } 85 | 86 | /** 87 | * User B view the customer_name after mask_show_first_4 88 | */ 89 | @Test 90 | public void testExecuteByUserB() { 91 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 92 | 93 | Object[][] expected = { 94 | {10001, "Jack", 102, "beijing"}, 95 | {10002, "Sallx", 105, "beijing"}, 96 | {10003, "Edwaxx", 106, "hangzhou"}, 97 | {10004, "John", 103, "hangzhou"}, 98 | {10005, "Edwaxx", 104, "shanghai"}, 99 | {10006, "Jack", 103, "shanghai"} 100 | }; 101 | executeDataMask(USER_B, sql, expected); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/test/java/com/hw/security/flink/execute/ExecuteRowFilterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package com.hw.security.flink.execute; 20 | 21 | import com.hw.security.flink.basic.AbstractBasicTest; 22 | 23 | import org.junit.BeforeClass; 24 | import org.junit.Ignore; 25 | import org.junit.Test; 26 | 27 | /** 28 | * Execute SQL based on row filter. 29 | * 30 | *
Note: Depending on the external Mysql environment, you can run it manually. 31 | * 32 | * @author: HamaWhite 33 | */ 34 | @Ignore 35 | public class ExecuteRowFilterTest extends AbstractBasicTest { 36 | 37 | @BeforeClass 38 | public static void init() { 39 | // create mysql cdc table orders 40 | createTableOfOrders(); 41 | 42 | // add row filter policies 43 | policyManager.addPolicy(rowFilterPolicy(USER_A, TABLE_ORDERS, "region = 'beijing'")); 44 | policyManager.addPolicy(rowFilterPolicy(USER_B, TABLE_ORDERS, "region = 'hangzhou'")); 45 | } 46 | 47 | /** 48 | * Execute without row-level filter 49 | */ 50 | @Test 51 | public void testExecute() { 52 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 53 | 54 | Object[][] expected = { 55 | {10001, "Jack", 102, "beijing"}, 56 | {10002, "Sally", 105, "beijing"}, 57 | {10003, "Edward", 106, "hangzhou"}, 58 | {10004, "John", 103, "hangzhou"}, 59 | {10005, "Edward", 104, "shanghai"}, 60 | {10006, "Jack", 103, "shanghai"} 61 | }; 62 | execute(sql, expected); 63 | } 64 | 65 | /** 66 | * User A can only view data in the beijing region 67 | */ 68 | @Test 69 | public void testExecuteByUserA() { 70 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 71 | 72 | Object[][] expected = { 73 | {10001, "Jack", 102, "beijing"}, 74 | {10002, "Sally", 105, "beijing"} 75 | }; 76 | executeRowFilter(USER_A, sql, expected); 77 | } 78 | 79 | /** 80 | * User B can only view data in the hangzhou region 81 | */ 82 | @Test 83 | public void testExecuteByUserB() { 84 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 85 | 86 | Object[][] expected = { 87 | {10003, "Edward", 106, "hangzhou"}, 88 | {10004, "John", 103, "hangzhou"} 89 | }; 90 | executeRowFilter(USER_B, sql, expected); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/com/hw/security/flink/execute/MixedExecuteTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package com.hw.security.flink.execute; 20 | 21 | import com.hw.security.flink.basic.AbstractBasicTest; 22 | 23 | import org.junit.BeforeClass; 24 | import org.junit.Ignore; 25 | import org.junit.Test; 26 | 27 | /** 28 | * Execute the single sql with user row-level filter and data mask policies. 29 | * 30 | *
Note: Depending on the external Mysql environment, you can run it manually. 31 | * 32 | * @author: HamaWhite 33 | */ 34 | @Ignore 35 | public class MixedExecuteTest extends AbstractBasicTest { 36 | 37 | @BeforeClass 38 | public static void init() { 39 | // create mysql cdc table orders 40 | createTableOfOrders(); 41 | 42 | // add row filter policies 43 | policyManager.addPolicy(rowFilterPolicy(USER_A, TABLE_ORDERS, "region = 'beijing'")); 44 | policyManager.addPolicy(rowFilterPolicy(USER_B, TABLE_ORDERS, "region = 'hangzhou'")); 45 | 46 | // add data mask policies 47 | policyManager.addPolicy(dataMaskPolicy(USER_A, TABLE_ORDERS, "customer_name", "MASK")); 48 | policyManager.addPolicy(dataMaskPolicy(USER_B, TABLE_ORDERS, "customer_name", "MASK_SHOW_FIRST_4")); 49 | } 50 | 51 | /** 52 | * Execute without row-level filter or data mask 53 | */ 54 | @Test 55 | public void testExecute() { 56 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 57 | 58 | Object[][] expected = { 59 | {10001, "Jack", 102, "beijing"}, 60 | {10002, "Sally", 105, "beijing"}, 61 | {10003, "Edward", 106, "hangzhou"}, 62 | {10004, "John", 103, "hangzhou"}, 63 | {10005, "Edward", 104, "shanghai"}, 64 | {10006, "Jack", 103, "shanghai"} 65 | }; 66 | execute(sql, expected); 67 | } 68 | 69 | /** 70 | * User A can only view data in the beijing region and the customer_name after mask 71 | */ 72 | @Test 73 | public void testExecuteByUserA() { 74 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 75 | 76 | Object[][] expected = { 77 | {10001, "Xxxx", 102, "beijing"}, 78 | {10002, "Xxxxx", 105, "beijing"} 79 | }; 80 | mixedExecute(USER_A, sql, expected); 81 | } 82 | 83 | /** 84 | * User B can only view data in the hangzhou region and the customer_name after mask_show_first_4 85 | */ 86 | @Test 87 | public void testExecuteByUserB() { 88 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 89 | 90 | Object[][] expected = { 91 | {10003, "Edwaxx", 106, "hangzhou"}, 92 | {10004, "John", 103, "hangzhou"} 93 | }; 94 | mixedExecute(USER_B, sql, expected); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/test/java/com/hw/security/flink/rewrite/MixedRewriteTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package com.hw.security.flink.rewrite; 20 | 21 | import com.hw.security.flink.basic.AbstractBasicTest; 22 | 23 | import org.junit.BeforeClass; 24 | import org.junit.Test; 25 | 26 | /** 27 | * Add row-level filter and column masking, then return new SQL. 28 | * 29 | * @author: HamaWhite 30 | */ 31 | public class MixedRewriteTest extends AbstractBasicTest { 32 | 33 | @BeforeClass 34 | public static void init() { 35 | // create mysql cdc table orders 36 | createTableOfOrders(); 37 | 38 | // create mysql cdc table products 39 | createTableOfProducts(); 40 | 41 | // add row filter policy 42 | policyManager.addPolicy(rowFilterPolicy(USER_A, TABLE_ORDERS, "region = 'beijing'")); 43 | policyManager.addPolicy(rowFilterPolicy(USER_A, TABLE_PRODUCTS, "name = 'hammer'")); 44 | 45 | // add data mask policies 46 | policyManager.addPolicy(dataMaskPolicy(USER_A, TABLE_ORDERS, "customer_name", "MASK")); 47 | policyManager.addPolicy(dataMaskPolicy(USER_A, TABLE_PRODUCTS, "name", "MASK_SHOW_LAST_4")); 48 | } 49 | 50 | /** 51 | * Only select 52 | */ 53 | @Test 54 | public void testSelect() { 55 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 56 | 57 | // the alias is equal to the table name orders 58 | String expected = "SELECT " + 59 | " orders.order_id ," + 60 | " orders.customer_name ," + 61 | " orders.product_id ," + 62 | " orders.region " + 63 | "FROM ( " + 64 | " SELECT " + 65 | " order_id ," + 66 | " order_date ," + 67 | " CAST(mask(customer_name) AS STRING) AS customer_name ," + 68 | " product_id ," + 69 | " price ," + 70 | " order_status ," + 71 | " region " + 72 | " FROM " + 73 | " hive.default.orders " + 74 | " ) AS orders " + 75 | "WHERE " + 76 | " orders.region = 'beijing' "; 77 | 78 | mixedRewrite(USER_A, sql, expected); 79 | } 80 | 81 | /** 82 | * The two tables of products and orders are left joined. 83 | *
products have an alias p, order has no alias 84 | */ 85 | @Test 86 | public void testJoin() { 87 | String sql = "SELECT " + 88 | " orders.order_id ," + 89 | " orders.customer_name ," + 90 | " orders.product_id ," + 91 | " orders.region ," + 92 | " p.name ," + 93 | " p.description " + 94 | "FROM " + 95 | " orders " + 96 | "LEFT JOIN " + 97 | " products AS p " + 98 | "ON " + 99 | " orders.product_id = p.id "; 100 | 101 | String expected = "SELECT " + 102 | " orders.order_id ," + 103 | " orders.customer_name ," + 104 | " orders.product_id ," + 105 | " orders.region ," + 106 | " p.name ," + 107 | " p.description " + 108 | "FROM ( " + 109 | " SELECT " + 110 | " order_id ," + 111 | " order_date ," + 112 | " CAST(mask(customer_name) AS STRING) AS customer_name ," + 113 | " product_id ," + 114 | " price ," + 115 | " order_status ," + 116 | " region " + 117 | " FROM " + 118 | " hive.default.orders " + 119 | " ) AS orders " + 120 | "LEFT JOIN ( " + 121 | " SELECT " + 122 | " id ," + 123 | " CAST(mask_show_last_n(name, 4, 'x', 'x', 'x', -1, '1') AS STRING) AS name, " + 124 | " description " + 125 | " FROM " + 126 | " hive.default.products " + 127 | " ) AS p " + 128 | "ON " + 129 | " orders.product_id = p.id " + 130 | "WHERE " + 131 | " orders.region = 'beijing' " + 132 | " AND p.name = 'hammer' "; 133 | 134 | mixedRewrite(USER_A, sql, expected); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/test/java/com/hw/security/flink/rewrite/RewriteDataMaskTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package com.hw.security.flink.rewrite; 20 | 21 | import com.hw.security.flink.basic.AbstractBasicTest; 22 | 23 | import org.junit.BeforeClass; 24 | import org.junit.Test; 25 | 26 | /** 27 | * Rewrite SQL based on data mask conditions 28 | * 29 | * @author: HamaWhite 30 | */ 31 | public class RewriteDataMaskTest extends AbstractBasicTest { 32 | 33 | @BeforeClass 34 | public static void init() { 35 | // create mysql cdc table orders 36 | createTableOfOrders(); 37 | 38 | // create mysql cdc table products 39 | createTableOfProducts(); 40 | 41 | // create mysql cdc table shipments 42 | createTableOfShipments(); 43 | 44 | // create print sink table print_sink 45 | createTableOfPrintSink(); 46 | 47 | // add data mask policies 48 | policyManager.addPolicy(dataMaskPolicy(USER_A, TABLE_ORDERS, "customer_name", "MASK")); 49 | policyManager.addPolicy(dataMaskPolicy(USER_A, TABLE_PRODUCTS, "name", "MASK_SHOW_LAST_4")); 50 | policyManager.addPolicy(dataMaskPolicy(USER_B, TABLE_ORDERS, "customer_name", "MASK_SHOW_FIRST_4")); 51 | } 52 | 53 | /** 54 | * Only select 55 | */ 56 | @Test 57 | public void testSelect() { 58 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 59 | 60 | // the alias is equal to the table name orders 61 | String expected = "SELECT " + 62 | " orders.order_id ," + 63 | " orders.customer_name ," + 64 | " orders.product_id ," + 65 | " orders.region " + 66 | "FROM ( " + 67 | " SELECT " + 68 | " order_id ," + 69 | " order_date ," + 70 | " CAST(mask(customer_name) AS STRING) AS customer_name ," + 71 | " product_id ," + 72 | " price ," + 73 | " order_status ," + 74 | " region " + 75 | " FROM " + 76 | " hive.default.orders " + 77 | " ) AS orders "; 78 | 79 | rewriteDataMask(USER_A, sql, expected); 80 | } 81 | 82 | /** 83 | * Only select with alias 84 | */ 85 | @Test 86 | public void testSelectWithAlias() { 87 | String sql = "SELECT o.order_id, o.customer_name, o.product_id, o.region FROM orders AS o"; 88 | 89 | // the alias is equal to 'o' 90 | String expected = "SELECT " + 91 | " o.order_id ," + 92 | " o.customer_name ," + 93 | " o.product_id ," + 94 | " o.region " + 95 | "FROM ( " + 96 | " SELECT " + 97 | " order_id ," + 98 | " order_date ," + 99 | " CAST(mask(customer_name) AS STRING) AS customer_name ," + 100 | " product_id ," + 101 | " price ," + 102 | " order_status ," + 103 | " region " + 104 | " FROM " + 105 | " hive.default.orders " + 106 | " ) AS o "; 107 | 108 | rewriteDataMask(USER_A, sql, expected); 109 | } 110 | 111 | /** 112 | * Different users configure different policies 113 | */ 114 | @Test 115 | public void testSelectDiffUser() { 116 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders"; 117 | 118 | String expectedUserA = "SELECT " + 119 | " orders.order_id ," + 120 | " orders.customer_name ," + 121 | " orders.product_id ," + 122 | " orders.region " + 123 | "FROM ( " + 124 | " SELECT " + 125 | " order_id ," + 126 | " order_date ," + 127 | " CAST(mask(customer_name) AS STRING) AS customer_name ," + 128 | " product_id ," + 129 | " price ," + 130 | " order_status ," + 131 | " region " + 132 | " FROM " + 133 | " hive.default.orders " + 134 | " ) AS orders "; 135 | 136 | String expectedUserB = "SELECT " + 137 | " orders.order_id ," + 138 | " orders.customer_name ," + 139 | " orders.product_id ," + 140 | " orders.region " + 141 | "FROM ( " + 142 | " SELECT " + 143 | " order_id ," + 144 | " order_date ," + 145 | " CAST(mask_show_first_n(customer_name, 4, 'x', 'x', 'x', -1, '1') AS STRING) " + 146 | " AS customer_name ," + 147 | " product_id ," + 148 | " price ," + 149 | " order_status ," + 150 | " region " + 151 | " FROM " + 152 | " hive.default.orders " + 153 | " ) AS orders "; 154 | 155 | rewriteDataMask(USER_A, sql, expectedUserA); 156 | rewriteDataMask(USER_B, sql, expectedUserB); 157 | } 158 | 159 | /** 160 | * The two tables of products and orders are left joined. 161 | *
products have an alias p, order has no alias
162 | */
163 | @Test
164 | public void testJoin() {
165 | String sql = "SELECT " +
166 | " orders.order_id ," +
167 | " orders.customer_name ," +
168 | " orders.product_id ," +
169 | " orders.region ," +
170 | " p.name ," +
171 | " p.description " +
172 | "FROM " +
173 | " orders " +
174 | "LEFT JOIN " +
175 | " products AS p " +
176 | "ON " +
177 | " orders.product_id = p.id ";
178 |
179 | String expected = "SELECT " +
180 | " orders.order_id ," +
181 | " orders.customer_name ," +
182 | " orders.product_id ," +
183 | " orders.region ," +
184 | " p.name ," +
185 | " p.description " +
186 | "FROM ( " +
187 | " SELECT " +
188 | " order_id ," +
189 | " order_date ," +
190 | " CAST(mask(customer_name) AS STRING) AS customer_name ," +
191 | " product_id ," +
192 | " price ," +
193 | " order_status ," +
194 | " region " +
195 | " FROM " +
196 | " hive.default.orders " +
197 | " ) AS orders " +
198 | "LEFT JOIN ( " +
199 | " SELECT " +
200 | " id ," +
201 | " CAST(mask_show_last_n(name, 4, 'x', 'x', 'x', -1, '1') AS STRING) AS name, " +
202 | " description " +
203 | " FROM " +
204 | " hive.default.products " +
205 | " ) AS p " +
206 | "ON " +
207 | " orders.product_id = p.id ";
208 |
209 | rewriteDataMask(USER_A, sql, expected);
210 | }
211 |
212 | /**
213 | * The products and orders two tables are left joined, and the left table comes from a sub-query
214 | */
215 | @Test
216 | public void testJoinSubQueryWhere() {
217 | String sql = "SELECT " +
218 | " o.order_id ," +
219 | " o.customer_name ," +
220 | " o.product_id ," +
221 | " o.region ," +
222 | " p.name ," +
223 | " p.description " +
224 | "FROM ( " +
225 | " SELECT " +
226 | " order_id ," +
227 | " customer_name ," +
228 | " price ," +
229 | " product_id ," +
230 | " region " +
231 | " FROM " +
232 | " orders " +
233 | " WHERE order_status = FALSE " +
234 | " ) AS o " +
235 | "LEFT JOIN " +
236 | " products AS p " +
237 | "ON " +
238 | " o.product_id = p.id " +
239 | "WHERE " +
240 | " o.price > 45.0 " +
241 | " OR o.customer_name = 'John' ";
242 |
243 | String expected = "SELECT " +
244 | " o.order_id ," +
245 | " o.customer_name ," +
246 | " o.product_id ," +
247 | " o.region ," +
248 | " p.name ," +
249 | " p.description " +
250 | "FROM ( " +
251 | " SELECT " +
252 | " orders.order_id ," +
253 | " orders.customer_name ," +
254 | " orders.price ," +
255 | " orders.product_id ," +
256 | " orders.region " +
257 | " FROM ( " +
258 | " SELECT " +
259 | " order_id ," +
260 | " order_date ," +
261 | " CAST(mask(customer_name) AS STRING) AS customer_name ," +
262 | " product_id ," +
263 | " price ," +
264 | " order_status ," +
265 | " region " +
266 | " FROM " +
267 | " hive.default.orders " +
268 | " ) AS orders " +
269 | " WHERE " +
270 | " orders.order_status = FALSE " +
271 | " ) AS o " +
272 | "LEFT JOIN ( " +
273 | " SELECT " +
274 | " id ," +
275 | " CAST(mask_show_last_n(name, 4, 'x', 'x', 'x', -1, '1') AS STRING) AS name ," +
276 | " description " +
277 | " FROM " +
278 | " hive.default.products " +
279 | " ) AS p " +
280 | "ON " +
281 | " o.product_id = p.id " +
282 | "WHERE " +
283 | " o.price > 45.0 " +
284 | " OR o.customer_name = 'John' ";
285 |
286 | rewriteDataMask(USER_A, sql, expected);
287 | }
288 |
289 | /**
290 | * The order table order, the product table products, and the logistics information table
291 | * shipments are associated with the three tables
292 | */
293 | @Test
294 | public void testThreeJoin() {
295 | String sql = "SELECT " +
296 | " o.order_id ," +
297 | " o.customer_name ," +
298 | " o.product_id ," +
299 | " o.region ," +
300 | " p.name ," +
301 | " p.description ," +
302 | " s.shipment_id ," +
303 | " s.origin ," +
304 | " s.destination ," +
305 | " s.is_arrived " +
306 | "FROM " +
307 | " orders AS o " +
308 | "LEFT JOIN " +
309 | " products AS p " +
310 | "ON " +
311 | " o.product_id = p.id " +
312 | "LEFT JOIN " +
313 | " shipments AS s " +
314 | "ON " +
315 | " o.order_id = s.order_id ";
316 |
317 | String expected = "SELECT " +
318 | " o.order_id ," +
319 | " o.customer_name ," +
320 | " o.product_id ," +
321 | " o.region ," +
322 | " p.name ," +
323 | " p.description ," +
324 | " s.shipment_id ," +
325 | " s.origin ," +
326 | " s.destination ," +
327 | " s.is_arrived " +
328 | "FROM ( " +
329 | " SELECT " +
330 | " order_id ," +
331 | " order_date ," +
332 | " CAST(mask(customer_name) AS STRING) AS customer_name ," +
333 | " product_id ," +
334 | " price ," +
335 | " order_status ," +
336 | " region " +
337 | " FROM " +
338 | " hive.default.orders " +
339 | " ) AS o " +
340 | "LEFT JOIN ( " +
341 | " SELECT " +
342 | " id ," +
343 | " CAST(mask_show_last_n(name, 4, 'x', 'x', 'x', -1, '1') AS STRING) AS name, " +
344 | " description " +
345 | " FROM " +
346 | " hive.default.products " +
347 | " ) AS p " +
348 | "ON " +
349 | " o.product_id = p.id " +
350 | "LEFT JOIN " +
351 | " hive.default.shipments AS s " +
352 | "ON " +
353 | " o.order_id = s.order_id ";
354 |
355 | rewriteDataMask(USER_A, sql, expected);
356 | }
357 |
358 | /**
359 | * insert-select.
360 | * insert into print table from mysql cdc stream table.
361 | */
362 | @Test
363 | public void testInsertSelect() {
364 | String sql = "INSERT INTO print_sink SELECT * FROM orders";
365 |
366 | // the following () is what Calcite would automatically add
367 | String expected = "INSERT INTO print_sink ( " +
368 | "SELECT " +
369 | " orders.order_id ," +
370 | " orders.order_date ," +
371 | " orders.customer_name ," +
372 | " orders.product_id ," +
373 | " orders.price ," +
374 | " orders.order_status ," +
375 | " orders.region " +
376 | "FROM ( " +
377 | " SELECT " +
378 | " order_id ," +
379 | " order_date ," +
380 | " CAST(mask(customer_name) AS STRING) AS customer_name ," +
381 | " product_id ," +
382 | " price ," +
383 | " order_status ," +
384 | " region " +
385 | " FROM " +
386 | " hive.default.orders " +
387 | " ) AS orders " +
388 | ") ";
389 |
390 | rewriteDataMask(USER_A, sql, expected);
391 | }
392 |
393 | /**
394 | * insert-select-select.
395 | * insert into print table from mysql cdc stream table.
396 | */
397 | @Test
398 | public void testInsertSelectSelect() {
399 | String sql = "INSERT INTO print_sink SELECT * FROM (SELECT * FROM orders) AS o";
400 |
401 | // the following () is what Calcite would automatically add
402 | String expected = "INSERT INTO print_sink ( " +
403 | "SELECT " +
404 | " o.order_id ," +
405 | " o.order_date ," +
406 | " o.customer_name ," +
407 | " o.product_id ," +
408 | " o.price ," +
409 | " o.order_status ," +
410 | " o.region " +
411 | "FROM ( " +
412 | " SELECT " +
413 | " orders.order_id ," +
414 | " orders.order_date ," +
415 | " orders.customer_name ," +
416 | " orders.product_id ," +
417 | " orders.price ," +
418 | " orders.order_status ," +
419 | " orders.region " +
420 | " FROM ( " +
421 | " SELECT " +
422 | " order_id ," +
423 | " order_date ," +
424 | " CAST(mask(customer_name) AS STRING) AS customer_name ," +
425 | " product_id ," +
426 | " price ," +
427 | " order_status ," +
428 | " region " +
429 | " FROM " +
430 | " hive.default.orders " +
431 | " ) AS orders " +
432 | " ) AS o " +
433 | ") ";
434 |
435 | rewriteDataMask(USER_A, sql, expected);
436 | }
437 | }
438 |
--------------------------------------------------------------------------------
/src/test/java/com/hw/security/flink/rewrite/RewriteRowFilterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package com.hw.security.flink.rewrite;
20 |
21 | import com.hw.security.flink.basic.AbstractBasicTest;
22 | import com.hw.security.flink.policy.RowFilterPolicy;
23 |
24 | import org.junit.BeforeClass;
25 | import org.junit.Test;
26 |
27 | /**
28 | * Rewrite SQL based on row filter conditions
29 | *
30 | * @author: HamaWhite
31 | */
32 | public class RewriteRowFilterTest extends AbstractBasicTest {
33 |
34 | @BeforeClass
35 | public static void init() {
36 | // create mysql cdc table orders
37 | createTableOfOrders();
38 |
39 | // create mysql cdc table products
40 | createTableOfProducts();
41 |
42 | // create mysql cdc table shipments
43 | createTableOfShipments();
44 |
45 | // create print sink table print_sink
46 | createTableOfPrintSink();
47 |
48 | // add row filter policies
49 | policyManager.addPolicy(rowFilterPolicy(USER_A, TABLE_ORDERS, "region = 'beijing'"));
50 | policyManager.addPolicy(rowFilterPolicy(USER_B, TABLE_ORDERS, "region = 'hangzhou'"));
51 | }
52 |
53 | /**
54 | * Only select
55 | */
56 | @Test
57 | public void testSelect() {
58 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders";
59 |
60 | String expected = "SELECT " +
61 | " orders.order_id ," +
62 | " orders.customer_name ," +
63 | " orders.product_id ," +
64 | " orders.region " +
65 | "FROM " +
66 | " hive.default.orders AS orders " +
67 | "WHERE " +
68 | " orders.region = 'beijing' ";
69 |
70 | rewriteRowFilter(USER_A, sql, expected);
71 | }
72 |
73 | /**
74 | * Different users configure different policies
75 | */
76 | @Test
77 | public void testSelectDiffUser() {
78 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders";
79 |
80 | String expectedUserA = "SELECT " +
81 | " orders.order_id ," +
82 | " orders.customer_name ," +
83 | " orders.product_id ," +
84 | " orders.region " +
85 | "FROM " +
86 | " hive.default.orders AS orders " +
87 | "WHERE " +
88 | " orders.region = 'beijing' ";
89 |
90 | String expectedUserB = "SELECT " +
91 | " orders.order_id ," +
92 | " orders.customer_name ," +
93 | " orders.product_id ," +
94 | " orders.region " +
95 | "FROM " +
96 | " hive.default.orders AS orders " +
97 | "WHERE " +
98 | " orders.region = 'hangzhou' ";
99 |
100 | rewriteRowFilter(USER_A, sql, expectedUserA);
101 | rewriteRowFilter(USER_B, sql, expectedUserB);
102 | }
103 |
104 | /**
105 | * Where there is a condition
106 | */
107 | @Test
108 | public void testSelectWhere() {
109 | String sql = "SELECT order_id, customer_name, product_id, region FROM orders WHERE price > 45.0";
110 |
111 | String expected = "SELECT " +
112 | " orders.order_id ," +
113 | " orders.customer_name ," +
114 | " orders.product_id ," +
115 | " orders.region " +
116 | "FROM " +
117 | " hive.default.orders AS orders " +
118 | "WHERE " +
119 | " orders.price > 45.0 " +
120 | " AND orders.region = 'beijing' ";
121 |
122 | rewriteRowFilter(USER_A, sql, expected);
123 | }
124 |
125 | /**
126 | * Where there is complex condition, add a pair of parentheses to the existing multiple where
127 | * conditions
128 | */
129 | @Test
130 | public void testSelectComplexWhere() {
131 | String sql = "SELECT " +
132 | " order_id ," +
133 | " customer_name ," +
134 | " product_id ," +
135 | " region " +
136 | "FROM " +
137 | " orders " +
138 | "WHERE " +
139 | " price > 45.0 " +
140 | " OR customer_name = 'John' ";
141 |
142 | String expected = "SELECT " +
143 | " orders.order_id ," +
144 | " orders.customer_name ," +
145 | " orders.product_id ," +
146 | " orders.region " +
147 | "FROM " +
148 | " hive.default.orders AS orders " +
149 | "WHERE " +
150 | " (orders.price > 45.0 OR orders.customer_name = 'John') " +
151 | " AND orders.region = 'beijing' ";
152 |
153 | rewriteRowFilter(USER_A, sql, expected);
154 | }
155 |
156 | /**
157 | * With group by clause
158 | */
159 | @Test
160 | public void testSelectWhereGroupBy() {
161 | String sql = "SELECT " +
162 | " customer_name ," +
163 | " count(*) AS cnt " +
164 | "FROM " +
165 | " orders " +
166 | "WHERE " +
167 | " price > 45.0 " +
168 | "GROUP BY " +
169 | " customer_name ";
170 |
171 | String expected = "SELECT " +
172 | " orders.customer_name ," +
173 | " COUNT(*) AS cnt " +
174 | "FROM " +
175 | " hive.default.orders AS orders " +
176 | "WHERE " +
177 | " orders.price > 45.0 " +
178 | " AND orders.region = 'beijing' " +
179 | "GROUP BY " +
180 | " orders.customer_name ";
181 |
182 | rewriteRowFilter(USER_A, sql, expected);
183 | }
184 |
185 | /**
186 | * The two tables of products and orders are left joined
187 | */
188 | @Test
189 | public void testJoin() {
190 | String sql = "SELECT " +
191 | " o.order_id ," +
192 | " o.customer_name ," +
193 | " o.product_id ," +
194 | " o.region ," +
195 | " p.name ," +
196 | " p.description " +
197 | "FROM " +
198 | " orders AS o " +
199 | "LEFT JOIN " +
200 | " products AS p " +
201 | "ON " +
202 | " o.product_id = p.id ";
203 |
204 | String expected = "SELECT " +
205 | " o.order_id ," +
206 | " o.customer_name ," +
207 | " o.product_id ," +
208 | " o.region ," +
209 | " p.name ," +
210 | " p.description " +
211 | "FROM " +
212 | " hive.default.orders AS o " +
213 | "LEFT JOIN " +
214 | " hive.default.products AS p " +
215 | "ON " +
216 | " o.product_id = p.id " +
217 | "WHERE " +
218 | " o.region = 'beijing' ";
219 |
220 | rewriteRowFilter(USER_A, sql, expected);
221 | }
222 |
223 | /**
224 | * The two tables of products and orders are left joined, but without alias
225 | */
226 | @Test
227 | public void testJoinWithoutAlias() {
228 | String sql = "SELECT " +
229 | " orders.order_id ," +
230 | " orders.customer_name ," +
231 | " orders.product_id ," +
232 | " orders.region ," +
233 | " products.name ," +
234 | " products.description " +
235 | "FROM " +
236 | " orders " +
237 | "LEFT JOIN " +
238 | " products " +
239 | "ON " +
240 | " orders.product_id = products.id ";
241 |
242 | String expected = "SELECT " +
243 | " orders.order_id ," +
244 | " orders.customer_name ," +
245 | " orders.product_id ," +
246 | " orders.region ," +
247 | " products.name ," +
248 | " products.description " +
249 | "FROM " +
250 | " hive.default.orders AS orders " +
251 | "LEFT JOIN " +
252 | " hive.default.products AS products " +
253 | "ON " +
254 | " orders.product_id = products.id " +
255 | "WHERE " +
256 | " orders.region = 'beijing' ";
257 |
258 | rewriteRowFilter(USER_A, sql, expected);
259 | }
260 |
261 | /**
262 | * The two tables of products and orders are left joined, and there is a condition
263 | */
264 | @Test
265 | public void testJoinWhere() {
266 | String sql = "SELECT " +
267 | " o.order_id ," +
268 | " o.customer_name ," +
269 | " o.product_id ," +
270 | " o.region ," +
271 | " p.name ," +
272 | " p.description " +
273 | "FROM " +
274 | " orders AS o " +
275 | "LEFT JOIN " +
276 | " products AS p " +
277 | "ON " +
278 | " o.product_id = p.id " +
279 | "WHERE " +
280 | " o.price > 45.0 " +
281 | " OR o.customer_name = 'John' ";
282 |
283 | String expected = "SELECT " +
284 | " o.order_id ," +
285 | " o.customer_name ," +
286 | " o.product_id ," +
287 | " o.region ," +
288 | " p.name ," +
289 | " p.description " +
290 | "FROM " +
291 | " hive.default.orders AS o " +
292 | "LEFT JOIN " +
293 | " hive.default.products AS p " +
294 | "ON " +
295 | " o.product_id = p.id " +
296 | "WHERE " +
297 | " (o.price > 45.0 OR o.customer_name = 'John') " +
298 | " AND o.region = 'beijing' ";
299 |
300 | rewriteRowFilter(USER_A, sql, expected);
301 | }
302 |
303 | /**
304 | * The products and orders two tables are left joined, and the left table comes from a sub-query
305 | */
306 | @Test
307 | public void testJoinSubQueryWhere() {
308 | String sql = "SELECT " +
309 | " o.order_id ," +
310 | " o.customer_name ," +
311 | " o.product_id ," +
312 | " o.region ," +
313 | " p.name ," +
314 | " p.description " +
315 | "FROM ( " +
316 | " SELECT " +
317 | " order_id ," +
318 | " customer_name ," +
319 | " price ," +
320 | " product_id ," +
321 | " region " +
322 | " FROM " +
323 | " orders " +
324 | " WHERE order_status = FALSE " +
325 | " ) AS o " +
326 | "LEFT JOIN " +
327 | " products AS p " +
328 | "ON " +
329 | " o.product_id = p.id " +
330 | "WHERE " +
331 | " o.price > 45.0 " +
332 | " OR o.customer_name = 'John' ";
333 |
334 | String expected = "SELECT " +
335 | " o.order_id ," +
336 | " o.customer_name ," +
337 | " o.product_id ," +
338 | " o.region ," +
339 | " p.name ," +
340 | " p.description " +
341 | "FROM ( " +
342 | " SELECT " +
343 | " orders.order_id ," +
344 | " orders.customer_name ," +
345 | " orders.price ," +
346 | " orders.product_id ," +
347 | " orders.region " +
348 | " FROM " +
349 | " hive.default.orders AS orders " +
350 | " WHERE " +
351 | " orders.order_status = FALSE " +
352 | " AND orders.region = 'beijing' " +
353 | " ) AS o " +
354 | "LEFT JOIN " +
355 | " hive.default.products AS p " +
356 | "ON " +
357 | " o.product_id = p.id " +
358 | "WHERE " +
359 | " o.price > 45.0 " +
360 | " OR o.customer_name = 'John' ";
361 |
362 | rewriteRowFilter(USER_A, sql, expected);
363 | }
364 |
365 | /**
366 | * The two tables of orders and products are joined, and both have row-level filter conditions
367 | */
368 | @Test
369 | public void testJoinWithBothPermissions() {
370 | RowFilterPolicy policy = rowFilterPolicy(USER_A, TABLE_PRODUCTS, "name = 'hammer'");
371 | // add policy
372 | policyManager.addPolicy(policy);
373 |
374 | String sql = "SELECT " +
375 | " o.order_id ," +
376 | " o.customer_name ," +
377 | " o.product_id ," +
378 | " o.region ," +
379 | " p.name ," +
380 | " p.description " +
381 | "FROM " +
382 | " orders AS o " +
383 | "LEFT JOIN " +
384 | " products AS p " +
385 | "ON " +
386 | " o.product_id = p.id ";
387 |
388 | String expected = "SELECT " +
389 | " o.order_id ," +
390 | " o.customer_name ," +
391 | " o.product_id ," +
392 | " o.region ," +
393 | " p.name ," +
394 | " p.description " +
395 | "FROM " +
396 | " hive.default.orders AS o " +
397 | "LEFT JOIN " +
398 | " hive.default.products AS p " +
399 | "ON " +
400 | " o.product_id = p.id " +
401 | "WHERE " +
402 | " o.region = 'beijing' " +
403 | " AND p.name = 'hammer' ";
404 |
405 | rewriteRowFilter(USER_A, sql, expected);
406 |
407 | // remove policy
408 | policyManager.removePolicy(policy);
409 | }
410 |
411 | /**
412 | * The order table order, the product table products, and the logistics information table
413 | * shipments are associated with the three tables
414 | */
415 | @Test
416 | public void testThreeJoin() {
417 | RowFilterPolicy policy1 = rowFilterPolicy(USER_A, TABLE_PRODUCTS, "name = 'hammer'");
418 | RowFilterPolicy policy2 = rowFilterPolicy(USER_A, TABLE_SHIPMENTS, "is_arrived = FALSE");
419 |
420 | // add policies
421 | policyManager.addPolicy(policy1);
422 | policyManager.addPolicy(policy2);
423 |
424 | String sql = "SELECT " +
425 | " o.order_id ," +
426 | " o.customer_name ," +
427 | " o.product_id ," +
428 | " o.region ," +
429 | " p.name ," +
430 | " p.description ," +
431 | " s.shipment_id ," +
432 | " s.origin ," +
433 | " s.destination ," +
434 | " s.is_arrived " +
435 | "FROM " +
436 | " orders AS o " +
437 | "LEFT JOIN " +
438 | " products AS p " +
439 | "ON " +
440 | " o.product_id = p.id " +
441 | "LEFT JOIN " +
442 | " shipments AS s " +
443 | "ON " +
444 | " o.order_id = s.order_id ";
445 |
446 | String expected = "SELECT " +
447 | " o.order_id ," +
448 | " o.customer_name ," +
449 | " o.product_id ," +
450 | " o.region ," +
451 | " p.name ," +
452 | " p.description ," +
453 | " s.shipment_id ," +
454 | " s.origin ," +
455 | " s.destination ," +
456 | " s.is_arrived " +
457 | "FROM " +
458 | " hive.default.orders AS o " +
459 | "LEFT JOIN " +
460 | " hive.default.products AS p " +
461 | "ON " +
462 | " o.product_id = p.id " +
463 | "LEFT JOIN " +
464 | " hive.default.shipments AS s " +
465 | "ON " +
466 | " o.order_id = s.order_id " +
467 | "WHERE " +
468 | " o.region = 'beijing' " +
469 | " AND p.name = 'hammer' " +
470 | " AND s.is_arrived = FALSE ";
471 |
472 | rewriteRowFilter(USER_A, sql, expected);
473 |
474 | // remove policies
475 | policyManager.removePolicy(policy1);
476 | policyManager.removePolicy(policy2);
477 | }
478 |
479 | /**
480 | * insert-select.
481 | * insert into print table from mysql cdc stream table.
482 | */
483 | @Test
484 | public void testInsertSelect() {
485 | String sql = "INSERT INTO print_sink SELECT * FROM orders";
486 |
487 | // the following () is what Calcite would automatically add
488 | String expected = "INSERT INTO print_sink ( " +
489 | "SELECT " +
490 | " orders.order_id ," +
491 | " orders.order_date ," +
492 | " orders.customer_name ," +
493 | " orders.product_id ," +
494 | " orders.price ," +
495 | " orders.order_status ," +
496 | " orders.region " +
497 | "FROM " +
498 | " hive.default.orders AS orders " +
499 | "WHERE " +
500 | " orders.region = 'beijing' " +
501 | ") ";
502 |
503 | rewriteRowFilter(USER_A, sql, expected);
504 | }
505 |
506 | /**
507 | * insert-select-select.
508 | * insert into print table from mysql cdc stream table.
509 | */
510 | @Test
511 | public void testInsertSelectSelect() {
512 | String sql = "INSERT INTO print_sink SELECT * FROM (SELECT * FROM orders) AS o";
513 |
514 | // the following () is what Calcite would automatically add
515 | String expected = "INSERT INTO print_sink ( " +
516 | "SELECT " +
517 | " o.order_id ," +
518 | " o.order_date ," +
519 | " o.customer_name ," +
520 | " o.product_id ," +
521 | " o.price ," +
522 | " o.order_status ," +
523 | " o.region " +
524 | "FROM ( " +
525 | " SELECT " +
526 | " orders.order_id ," +
527 | " orders.order_date ," +
528 | " orders.customer_name ," +
529 | " orders.product_id ," +
530 | " orders.price ," +
531 | " orders.order_status ," +
532 | " orders.region " +
533 | " FROM " +
534 | " hive.default.orders AS orders " +
535 | " WHERE " +
536 | " orders.region = 'beijing' " +
537 | " ) AS o " +
538 | ") ";
539 |
540 | rewriteRowFilter(USER_A, sql, expected);
541 | }
542 | }
--------------------------------------------------------------------------------
/src/test/resources/hive-site.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |