Skip to content

Commit fe7be4e

Browse files
authored
Fixed an issue with subpaths in resources policies (#2856)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
1 parent b460354 commit fe7be4e

File tree

11 files changed

+161
-8
lines changed

11 files changed

+161
-8
lines changed

portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ const BrowserHandler = () => {
214214
}
215215

216216
const permitItems = permissionItems(
217-
bucketName,
217+
response.bucketName || bucketName,
218218
pathPrefix,
219219
allowResources || []
220220
);

portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/types.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export interface WebsocketResponse {
4646
request_end?: boolean;
4747
data?: ObjectResponse[];
4848
prefix?: string;
49+
bucketName?: string;
4950
}
5051

5152
export interface ObjectResponse {

portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ export const permissionItems = (
296296
return null;
297297
}
298298

299-
const returnElements: BucketObjectItem[] = [];
299+
let returnElements: BucketObjectItem[] = [];
300300

301301
// We split current path
302302
const splitCurrentPath = currentPath.split("/");
@@ -354,6 +354,14 @@ export const permissionItems = (
354354

355355
let pathToRouteElements: string[] = [];
356356

357+
// We verify if currentPath is contained in the path begin, if is not contained the user has no access to this subpath
358+
const cleanCurrPath = currentPath.replace(/\/$/, "");
359+
360+
if (!prefixItem.startsWith(cleanCurrPath) && currentPath !== "") {
361+
return;
362+
}
363+
364+
// For every split element we iterate and check if we can construct a URL
357365
splitItems.every((splitElement, index) => {
358366
if (!splitElement.includes("*") && splitElement !== "") {
359367
if (splitElement !== splitCurrentPath[index]) {
@@ -380,5 +388,20 @@ export const permissionItems = (
380388
}
381389
});
382390

391+
// We clean duplicated name entries
392+
if (returnElements.length > 0) {
393+
let clElements: BucketObjectItem[] = [];
394+
let keys: string[] = [];
395+
396+
returnElements.forEach((itm) => {
397+
if (!keys.includes(itm.name)) {
398+
clElements.push(itm);
399+
keys.push(itm.name);
400+
}
401+
});
402+
403+
returnElements = clElements;
404+
}
405+
383406
return returnElements;
384407
};

portal-ui/tests/permissions-7/resourceTesting.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,14 @@ import {
2525
fixture("Test resources policy").page("http://localhost:9090/");
2626

2727
const bucket1 = "testcondition";
28+
const bucket3 = "my-company";
2829
const test1BucketBrowseButton = namedTestBucketBrowseButtonFor(bucket1);
30+
const test3BucketBrowseButton = namedTestBucketBrowseButtonFor(bucket3);
2931
export const file = Selector(".ReactVirtualized__Table__rowColumn").withText(
3032
"test.txt"
3133
);
34+
export const deniedError = Selector(".message-text").withText("Access Denied.");
35+
3236
test
3337
.before(async (t) => {
3438
await functions.setUpNamedBucket(t, bucket1);
@@ -142,3 +146,71 @@ test
142146
.after(async (t) => {
143147
await functions.cleanUpNamedBucketAndUploads(t, bucket1);
144148
});
149+
150+
test
151+
.before(async (t) => {
152+
await functions.setUpNamedBucket(t, bucket3);
153+
await functions.uploadNamedObjectToBucket(
154+
t,
155+
bucket3,
156+
"test.txt",
157+
"portal-ui/tests/uploads/test.txt"
158+
);
159+
await functions.uploadNamedObjectToBucket(
160+
t,
161+
bucket3,
162+
"home/UserY/test.txt",
163+
"portal-ui/tests/uploads/test.txt"
164+
);
165+
await functions.uploadNamedObjectToBucket(
166+
t,
167+
bucket3,
168+
"home/UserX/test.txt",
169+
"portal-ui/tests/uploads/test.txt"
170+
);
171+
await functions.uploadNamedObjectToBucket(
172+
t,
173+
bucket3,
174+
"home/User/test.txt",
175+
"portal-ui/tests/uploads/test.txt"
176+
);
177+
await functions.uploadNamedObjectToBucket(
178+
t,
179+
bucket3,
180+
"home/User/secondlevel/thirdlevel/test.txt",
181+
"portal-ui/tests/uploads/test.txt"
182+
);
183+
})("User can browse from sub levels as policy has wildcard", async (t) => {
184+
await t
185+
.useRole(roles.conditions3)
186+
.navigateTo(`http://localhost:9090/browser`)
187+
.click(test3BucketBrowseButton)
188+
.wait(1500)
189+
.click(Selector(".ReactVirtualized__Table__rowColumn").withText("home"))
190+
.wait(1500)
191+
.click(Selector(".ReactVirtualized__Table__rowColumn").withText("User"))
192+
.wait(1500)
193+
.expect(file.exists)
194+
.ok()
195+
.click(
196+
Selector(".ReactVirtualized__Table__rowColumn").withText("secondlevel")
197+
)
198+
.wait(1500)
199+
.click(
200+
Selector(".ReactVirtualized__Table__rowColumn").withText("thirdlevel")
201+
)
202+
.wait(1500)
203+
.expect(file.exists)
204+
.ok()
205+
.navigateTo(`http://localhost:9090/browser`)
206+
.click(test3BucketBrowseButton)
207+
.wait(1500)
208+
.click(Selector(".ReactVirtualized__Table__rowColumn").withText("home"))
209+
.wait(1500)
210+
.click(Selector(".ReactVirtualized__Table__rowColumn").withText("UserX"))
211+
.expect(deniedError.exists)
212+
.ok();
213+
})
214+
.after(async (t) => {
215+
await functions.cleanUpNamedBucketAndUploads(t, bucket3);
216+
});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"Version": "2012-10-17",
3+
"Statement": [
4+
{
5+
"Sid": "AllowUserToSeeBucketListInTheConsole",
6+
"Action": ["s3:ListAllMyBuckets", "s3:GetBucketLocation"],
7+
"Effect": "Allow",
8+
"Resource": ["arn:aws:s3:::*"]
9+
},
10+
{
11+
"Sid": "AllowRootAndHomeListingOfCompanyBucket",
12+
"Action": ["s3:ListBucket"],
13+
"Effect": "Allow",
14+
"Resource": ["arn:aws:s3:::my-company"],
15+
"Condition": {
16+
"StringEquals": {
17+
"s3:prefix": ["", "home/", "home/User"],
18+
"s3:delimiter": ["/"]
19+
}
20+
}
21+
},
22+
{
23+
"Sid": "AllowListingOfUserFolder",
24+
"Action": ["s3:ListBucket"],
25+
"Effect": "Allow",
26+
"Resource": ["arn:aws:s3:::my-company"],
27+
"Condition": { "StringLike": { "s3:prefix": ["home/User/*"] } }
28+
},
29+
{
30+
"Sid": "AllowAllS3ActionsInUserFolder",
31+
"Effect": "Allow",
32+
"Action": ["s3:*"],
33+
"Resource": ["arn:aws:s3:::my-company/home/User/*"]
34+
}
35+
]
36+
}

portal-ui/tests/scripts/cleanup-env.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ remove_users() {
3030
mc admin user remove minio prefix-policy-ui-crash-$TIMESTAMP
3131
mc admin user remove minio conditions-$TIMESTAMP
3232
mc admin user remove minio conditions-2-$TIMESTAMP
33+
mc admin user remove minio conditions-3-$TIMESTAMP
3334
}
3435

3536
remove_policies() {
@@ -54,6 +55,7 @@ remove_policies() {
5455
mc admin policy remove minio fix-prefix-policy-ui-crash-$TIMESTAMP
5556
mc admin policy remove minio conditions-policy-$TIMESTAMP
5657
mc admin policy remove minio conditions-policy-2-$TIMESTAMP
58+
mc admin policy remove minio conditions-policy-3-$TIMESTAMP
5759
}
5860

5961
__init__() {

portal-ui/tests/scripts/common.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ create_policies() {
4848
mc admin policy create minio delete-object-with-prefix-$TIMESTAMP portal-ui/tests/policies/deleteObjectWithPrefix.json
4949
mc admin policy create minio conditions-policy-$TIMESTAMP portal-ui/tests/policies/conditionsPolicy.json
5050
mc admin policy create minio conditions-policy-2-$TIMESTAMP portal-ui/tests/policies/conditionsPolicy2.json
51+
mc admin policy create minio conditions-policy-3-$TIMESTAMP portal-ui/tests/policies/conditionsPolicy3.json
5152
}
5253

5354
create_users() {
@@ -77,6 +78,7 @@ create_users() {
7778
mc admin user add minio delete-object-with-prefix-$TIMESTAMP deleteobjectwithprefix1234
7879
mc admin user add minio conditions-$TIMESTAMP conditions1234
7980
mc admin user add minio conditions-2-$TIMESTAMP conditions1234
81+
mc admin user add minio conditions-3-$TIMESTAMP conditions1234
8082
}
8183

8284
create_buckets() {
@@ -111,4 +113,5 @@ assign_policies() {
111113
mc admin policy attach minio delete-object-with-prefix-$TIMESTAMP --user delete-object-with-prefix-$TIMESTAMP
112114
mc admin policy attach minio conditions-policy-$TIMESTAMP --user conditions-$TIMESTAMP
113115
mc admin policy attach minio conditions-policy-2-$TIMESTAMP --user conditions-2-$TIMESTAMP
116+
mc admin policy attach minio conditions-policy-3-$TIMESTAMP --user conditions-3-$TIMESTAMP
114117
}

portal-ui/tests/scripts/permissions.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ remove_users() {
3838
mc admin user remove minio delete-object-with-prefix-"$TIMESTAMP"
3939
mc admin user remove minio conditions-"$TIMESTAMP"
4040
mc admin user remove minio conditions-2-"$TIMESTAMP"
41+
mc admin user remove minio conditions-3-"$TIMESTAMP"
4142
}
4243

4344
remove_policies() {
@@ -63,6 +64,7 @@ remove_policies() {
6364
mc admin policy remove minio delete-object-with-prefix-"$TIMESTAMP"
6465
mc admin policy remove conditions-policy-"$TIMESTAMP"
6566
mc admin policy remove conditions-policy-2-"$TIMESTAMP"
67+
mc admin policy remove conditions-policy-3-"$TIMESTAMP"
6668
}
6769

6870
remove_buckets() {

portal-ui/tests/utils/roles.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,3 +272,14 @@ export const conditions2 = Role(
272272
},
273273
{ preserveUrl: true }
274274
);
275+
276+
export const conditions3 = Role(
277+
loginUrl,
278+
async (t) => {
279+
await t
280+
.typeText("#accessKey", "conditions-3-" + unixTimestamp)
281+
.typeText("#secretKey", "conditions1234")
282+
.click(submitButton);
283+
},
284+
{ preserveUrl: true }
285+
);

restapi/admin_objects.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type WSResponse struct {
4444
Error string `json:"error,omitempty"`
4545
RequestEnd bool `json:"request_end,omitempty"`
4646
Prefix string `json:"prefix,omitempty"`
47+
BucketName string `json:"bucketName,omitempty"`
4748
Data []ObjectResponse `json:"data,omitempty"`
4849
}
4950

0 commit comments

Comments
 (0)