Skip to content

Commit 2f8f16a

Browse files
committed
[MCG NC] Bucket policy with deny statement using NotPrincipal also denies the principal
This is the put-bucket-policy case for combination of Effect : DENY, Action: $OPERATION, NotPrincipal: $ACCOUNT The $ACCOUNT mentioned in the "NotPrincipal" should be excluded from DENy operation and should be allowed on the $OPERATION Example: For operation get_object, if we have DENY effect for * (all accounts) and we want to give access to any one or few accounts, then that account can be part of "NotPrincipal" Fixes: https://issues.redhat.com/browse/DFBUGS-1519 Signed-off-by: Vinayakswami Hariharmath <[email protected]>
1 parent a3bc7dd commit 2f8f16a

File tree

2 files changed

+24
-12
lines changed

2 files changed

+24
-12
lines changed

src/endpoint/s3/s3_bucket_policy_utils.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,31 @@ async function _is_object_tag_fit(req, predicate, value) {
137137
return res;
138138
}
139139

140-
async function has_bucket_policy_permission(policy, account, method, arn_path, req) {
140+
async function has_bucket_policy_permission(policy, account, method, arn_path, req, account_identifier_name = undefined) {
141141
const [allow_statements, deny_statements] = _.partition(policy.Statement, statement => statement.Effect === 'Allow');
142142

143143
// the case where the permission is an array started in op get_object_attributes
144144
const method_arr = Array.isArray(method) ? method : [method];
145145

146146
// look for explicit denies
147-
const res_arr_deny = await is_statement_fit_of_method_array(deny_statements, account, method_arr, arn_path, req);
147+
const res_arr_deny = await is_statement_fit_of_method_array(deny_statements,
148+
account,
149+
method_arr,
150+
arn_path,
151+
req,
152+
account_identifier_name
153+
);
148154
if (res_arr_deny.every(item => item)) return 'DENY';
149155

150156
// look for explicit allows
151-
const res_arr_allow = await is_statement_fit_of_method_array(allow_statements, account, method_arr, arn_path, req);
157+
const res_arr_allow = await is_statement_fit_of_method_array(
158+
allow_statements,
159+
account,
160+
method_arr,
161+
arn_path,
162+
req,
163+
account_identifier_name
164+
);
152165
if (res_arr_allow.every(item => item)) return 'ALLOW';
153166

154167
// implicit deny
@@ -168,14 +181,13 @@ function _is_action_fit(method, statement) {
168181
return statement.Action ? action_fit : !action_fit;
169182
}
170183

171-
function _is_principal_fit(account, statement) {
184+
function _is_principal_fit(account, statement, account_identifier_name = undefined) {
172185
let statement_principal = statement.Principal || statement.NotPrincipal;
173-
174186
let principal_fit = false;
175187
statement_principal = statement_principal.AWS ? statement_principal.AWS : statement_principal;
176188
for (const principal of _.flatten([statement_principal])) {
177189
dbg.log1('bucket_policy: ', statement.Principal ? 'Principal' : 'NotPrincipal', ' fit?', principal, account);
178-
if ((principal.unwrap() === '*') || (principal.unwrap() === account)) {
190+
if ((principal.unwrap() === '*') || (principal.unwrap() === account) || (account_identifier_name && (principal.unwrap() === account_identifier_name))) {
179191
principal_fit = true;
180192
break;
181193
}
@@ -198,15 +210,15 @@ function _is_resource_fit(arn_path, statement) {
198210
return statement.Resource ? resource_fit : !resource_fit;
199211
}
200212

201-
async function is_statement_fit_of_method_array(statements, account, method_arr, arn_path, req) {
213+
async function is_statement_fit_of_method_array(statements, account, method_arr, arn_path, req, account_identifier_name = undefined) {
202214
return Promise.all(method_arr.map(method_permission =>
203-
_is_statements_fit(statements, account, method_permission, arn_path, req)));
215+
_is_statements_fit(statements, account, method_permission, arn_path, req, account_identifier_name)));
204216
}
205217

206-
async function _is_statements_fit(statements, account, method, arn_path, req) {
218+
async function _is_statements_fit(statements, account, method, arn_path, req, account_identifier_name = undefined) {
207219
for (const statement of statements) {
208220
const action_fit = _is_action_fit(method, statement);
209-
const principal_fit = _is_principal_fit(account, statement);
221+
const principal_fit = _is_principal_fit(account, statement, account_identifier_name);
210222
const resource_fit = _is_resource_fit(arn_path, statement);
211223
const condition_fit = await _is_condition_fit(statement, req, method);
212224

src/endpoint/s3/s3_rest.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,14 +287,14 @@ async function authorize_request_policy(req) {
287287
// we start the permission check on account identifier intentionally
288288
if (account_identifier_id) {
289289
permission_by_id = await s3_bucket_policy_utils.has_bucket_policy_permission(
290-
s3_policy, account_identifier_id, method, arn_path, req);
290+
s3_policy, account_identifier_id, method, arn_path, req, account_identifier_name);
291291
dbg.log3('authorize_request_policy: permission_by_id', permission_by_id);
292292
}
293293
if (permission_by_id === "DENY") throw new S3Error(S3Error.AccessDenied);
294294

295295
if ((!account_identifier_id || permission_by_id !== "DENY") && account.owner === undefined) {
296296
permission_by_name = await s3_bucket_policy_utils.has_bucket_policy_permission(
297-
s3_policy, account_identifier_name, method, arn_path, req);
297+
s3_policy, {account_identifier_name, account_identifier_id}, method, arn_path, req, account_identifier_name);
298298
dbg.log3('authorize_request_policy: permission_by_name', permission_by_name);
299299
}
300300
if (permission_by_name === "DENY") throw new S3Error(S3Error.AccessDenied);

0 commit comments

Comments
 (0)