Skip to content

Commit 0e212e1

Browse files
committed
feat(query): prevent masking/row access policy name conflicts
1 parent a75e78d commit 0e212e1

File tree

4 files changed

+73
-3
lines changed

4 files changed

+73
-3
lines changed

src/meta/api/src/data_mask_api_impl.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use databend_common_meta_app::data_mask::MaskPolicyTableIdIdent;
2424
use databend_common_meta_app::data_mask::MaskPolicyTableIdListIdent;
2525
use databend_common_meta_app::data_mask::MaskpolicyTableIdList;
2626
use databend_common_meta_app::id_generator::IdGenerator;
27+
use databend_common_meta_app::row_access_policy::RowAccessPolicyNameIdent;
2728
use databend_common_meta_app::schema::CreateOption;
2829
use databend_common_meta_app::tenant::Tenant;
2930
use databend_common_meta_app::KeyWithTenant;
@@ -92,6 +93,17 @@ impl<KV: kvapi::KVApi<Error = MetaError>> DatamaskApi for KV {
9293
};
9394
}
9495

96+
let row_access_name_ident = RowAccessPolicyNameIdent::new(
97+
name_ident.tenant().clone(),
98+
name_ident.data_mask_name().to_string(),
99+
);
100+
if self.get_pb(&row_access_name_ident).await?.is_some() {
101+
return Err(AppError::DatamaskAlreadyExists(
102+
name_ident.exist_error("name conflicts with an existing row access policy"),
103+
)
104+
.into());
105+
}
106+
95107
// Create data mask by inserting these record:
96108
// name -> id
97109
// id -> policy
@@ -113,6 +125,8 @@ impl<KV: kvapi::KVApi<Error = MetaError>> DatamaskApi for KV {
113125
let meta: DatamaskMeta = req.data_mask_meta.clone();
114126
let id_list = MaskpolicyTableIdList::default();
115127
txn.condition.push(txn_cond_eq_seq(name_ident, curr_seq));
128+
txn.condition
129+
.push(txn_cond_eq_seq(&row_access_name_ident, 0));
116130
txn.if_then.extend(vec![
117131
txn_op_put_pb(name_ident, &id, None)?, // name -> db_id
118132
txn_op_put_pb(&id_ident, &meta, None)?, // id -> meta

src/meta/api/src/row_access_policy_api_impl.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use databend_common_meta_app::data_mask::DataMaskNameIdent;
1516
use databend_common_meta_app::id_generator::IdGenerator;
1617
use databend_common_meta_app::row_access_policy::row_access_policy_name_ident;
1718
use databend_common_meta_app::row_access_policy::row_access_policy_table_id_ident::RowAccessPolicyIdTableId;
@@ -86,6 +87,16 @@ impl<KV: kvapi::KVApi<Error = MetaError>> RowAccessPolicyApi for KV {
8687
}
8788
}
8889

90+
let mask_name_ident = DataMaskNameIdent::new(
91+
name_ident.tenant().clone(),
92+
name_ident.row_access_name().to_string(),
93+
);
94+
if self.get_pb(&mask_name_ident).await?.is_some() {
95+
return Ok(Err(
96+
name_ident.exist_error("name conflicts with an existing masking policy")
97+
));
98+
}
99+
89100
// Create row policy by inserting these record:
90101
// name -> id
91102
// id -> policy
@@ -102,6 +113,7 @@ impl<KV: kvapi::KVApi<Error = MetaError>> RowAccessPolicyApi for KV {
102113
{
103114
let meta: RowAccessPolicyMeta = req.row_access_policy_meta.clone();
104115
txn.condition.push(txn_cond_eq_seq(name_ident, curr_seq));
116+
txn.condition.push(txn_cond_eq_seq(&mask_name_ident, 0));
105117
txn.if_then.extend(vec![
106118
txn_op_put_pb(name_ident, &id, None)?, // name -> policy_id
107119
txn_op_put_pb(&id_ident, &meta, None)?, // id -> meta

tests/sqllogictests/suites/ee/05_ee_ddl/05_0004_ddl_security_policy.test

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,3 @@ DROP MASKING POLICY mask_ssn_conditional;
10891089

10901090
statement ok
10911091
unset global enable_planner_cache;
1092-
1093-
statement ok
1094-
unset global enable_experimental_row_access_policy;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
## Copyright 2023 Databend Cloud
2+
##
3+
## Licensed under the Elastic License, Version 2.0 (the "License");
4+
## you may not use this file except in compliance with the License.
5+
## You may obtain a copy of the License at
6+
##
7+
## https://www.elastic.co/licensing/elastic-license
8+
##
9+
## Unless required by applicable law or agreed to in writing, software
10+
## distributed under the License is distributed on an "AS IS" BASIS,
11+
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
## See the License for the specific language governing permissions and
13+
## limitations under the License.
14+
15+
statement ok
16+
set global enable_experimental_row_access_policy = 1;
17+
18+
## Cross-type policy name conflicts should be rejected
19+
statement ok
20+
drop row access policy if exists shared_policy_name;
21+
22+
statement ok
23+
drop masking policy if exists shared_policy_name;
24+
25+
statement ok
26+
CREATE ROW ACCESS POLICY shared_policy_name AS (user_id STRING) RETURNS boolean -> true;
27+
28+
statement error 2321
29+
CREATE MASKING POLICY shared_policy_name AS (val STRING) RETURNS STRING -> '***';
30+
31+
statement ok
32+
drop row access policy if exists shared_policy_name;
33+
34+
statement ok
35+
drop masking policy if exists mask_only_name;
36+
37+
statement ok
38+
drop row access policy if exists mask_only_name;
39+
40+
statement ok
41+
CREATE MASKING POLICY mask_only_name AS (val STRING) RETURNS STRING -> '***';
42+
43+
statement error 2324
44+
CREATE ROW ACCESS POLICY mask_only_name AS (user_id STRING) RETURNS boolean -> true;
45+
46+
statement ok
47+
drop masking policy if exists mask_only_name;

0 commit comments

Comments
 (0)