Added missing permissions validation to rewind button (#3282)

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2024-04-04 23:41:20 -06:00
committed by GitHub
parent 6c50c38f83
commit 963c8f1221
10 changed files with 217 additions and 14 deletions

View File

@@ -22,7 +22,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.21.8
go-version: 1.21.9
check-latest: true
- name: Get official govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@latest

2
go.mod
View File

@@ -33,7 +33,7 @@ require (
github.com/tidwall/gjson v1.17.1
github.com/unrolled/secure v1.14.0
golang.org/x/crypto v0.21.0
golang.org/x/net v0.22.0
golang.org/x/net v0.23.0
golang.org/x/oauth2 v0.18.0
// Added to include security fix for
// https://github.com/golang/go/issues/56152

4
go.sum
View File

@@ -352,8 +352,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

View File

@@ -26,6 +26,7 @@ import get from "lodash/get";
import {
AccessRuleIcon,
ActionsList,
Badge,
Box,
BucketsIcon,
Button,
@@ -39,7 +40,6 @@ import {
RefreshIcon,
ScreenTitle,
ShareIcon,
Badge,
} from "mds";
import { api } from "api";
import { errorToHandler } from "api/errors";
@@ -274,6 +274,11 @@ const ListObjects = () => {
[pathAsResourceInPolicy, ...sessionGrantWildCards],
[IAM_SCOPES.S3_GET_OBJECT, IAM_SCOPES.S3_GET_ACTIONS],
);
const canRewind = hasPermission(bucketName, [
IAM_SCOPES.S3_GET_OBJECT,
IAM_SCOPES.S3_GET_ACTIONS,
IAM_SCOPES.S3_GET_BUCKET_VERSIONING,
]);
const canDelete = hasPermission(
[pathAsResourceInPolicy, ...sessionGrantWildCards],
[IAM_SCOPES.S3_DELETE_OBJECT],
@@ -1057,7 +1062,20 @@ const ListObjects = () => {
actions={
<Fragment>
{!anonymousMode && (
<TooltipWrapper tooltip={"Rewind Bucket"}>
<TooltipWrapper
tooltip={
canRewind
? "Rewind Bucket"
: permissionTooltipHelper(
[
IAM_SCOPES.S3_GET_OBJECT,
IAM_SCOPES.S3_GET_ACTIONS,
IAM_SCOPES.S3_GET_BUCKET_VERSIONING,
],
"apply rewind in this bucket",
)
}
>
<Button
id={"rewind-objects-list"}
label={"Rewind"}
@@ -1078,13 +1096,7 @@ const ListObjects = () => {
onClick={() => {
setRewindSelect(true);
}}
disabled={
!isVersioningApplied ||
!hasPermission(bucketName, [
IAM_SCOPES.S3_GET_OBJECT,
IAM_SCOPES.S3_GET_ACTIONS,
])
}
disabled={!isVersioningApplied || !canRewind}
/>
</TooltipWrapper>
)}

View File

@@ -17,10 +17,20 @@
import * as roles from "../utils/roles";
import * as elements from "../utils/elements";
import * as functions from "../utils/functions";
import { testBucketBrowseButtonFor } from "../utils/functions";
import {
namedTestBucketBrowseButtonFor,
setUpNamedBucket,
setVersionedBucket,
testBucketBrowseButtonFor,
} from "../utils/functions";
import { Selector } from "testcafe";
import { deniedError, file } from "../permissions-6/resourceTesting";
fixture("Rewind Testing").page("http://localhost:9090");
const bucketname = "bucketname";
const test3BucketBrowseButton = namedTestBucketBrowseButtonFor(bucketname);
test
.before(async (t) => {
// Create a bucket
@@ -57,3 +67,80 @@ test
// Cleanup created bucket and corresponding uploads
await functions.cleanUpBucketAndUploads(t, "abucketrewind");
});
test
.before(async (t) => {
await functions.setUpNamedBucket(t, bucketname);
await functions.setVersionedBucket(t, bucketname);
await functions.uploadNamedObjectToBucket(
t,
bucketname,
"test.txt",
"web-app/tests/uploads/test.txt",
);
await functions.uploadNamedObjectToBucket(
t,
bucketname,
"firstlevel/secondlevel/test.txt",
"web-app/tests/uploads/test.txt",
);
})("Rewind button enabled in bucket", async (t) => {
await t
.useRole(roles.rewindEnabled)
.navigateTo(`http://localhost:9090/browser`)
.click(test3BucketBrowseButton)
.wait(1500)
.click(
Selector(".ReactVirtualized__Table__rowColumn").withText("firstlevel"),
)
.wait(1500)
.click(
Selector(".ReactVirtualized__Table__rowColumn").withText("secondlevel"),
)
.wait(1500)
.expect(elements.rewindButton.exists)
.ok();
})
.after(async (t) => {
await functions.cleanUpNamedBucketAndUploads(t, bucketname);
});
test
.before(async (t) => {
await functions.setUpNamedBucket(t, bucketname);
await functions.setVersionedBucket(t, bucketname);
await functions.uploadNamedObjectToBucket(
t,
bucketname,
"test.txt",
"web-app/tests/uploads/test.txt",
);
await functions.uploadNamedObjectToBucket(
t,
bucketname,
"firstlevel/secondlevel/test.txt",
"web-app/tests/uploads/test.txt",
);
})("Rewind button disabled in bucket", async (t) => {
await t
.useRole(roles.rewindNotEnabled)
.navigateTo(`http://localhost:9090/browser`)
.click(test3BucketBrowseButton)
.wait(1500)
.click(
Selector(".ReactVirtualized__Table__rowColumn").withText("firstlevel"),
)
.wait(1500)
.click(
Selector(".ReactVirtualized__Table__rowColumn").withText("secondlevel"),
)
.wait(1500)
.expect(elements.rewindButton.exists)
.ok()
.wait(1500)
.expect(elements.rewindButton.hasAttribute("disabled"))
.ok();
})
.after(async (t) => {
await functions.cleanUpNamedBucketAndUploads(t, bucketname);
});

View File

@@ -0,0 +1,36 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": ["s3:CreateBucket", "s3:DeleteBucket"],
"Resource": ["arn:aws:s3:::*"]
},
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::bucketname"]
},
{
"Effect": "Allow",
"Action": ["s3:GetBucketLocation", "s3:GetBucketVersioning"],
"Resource": ["arn:aws:s3:::bucketname"]
},
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": [
"arn:aws:s3:::bucketname/firstlevel",
"arn:aws:s3:::bucketname/firstlevel/*"
]
},
{
"Effect": "Allow",
"Action": ["s3:*"],
"Resource": [
"arn:aws:s3:::bucketname/firstlevel/secondlevel*",
"arn:aws:s3:::bucketname/firstlevel/secondlevel/*"
]
}
]
}

View File

@@ -0,0 +1,36 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": ["s3:CreateBucket", "s3:DeleteBucket"],
"Resource": ["arn:aws:s3:::*"]
},
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::bucketname"]
},
{
"Effect": "Allow",
"Action": ["s3:GetBucketLocation"],
"Resource": ["arn:aws:s3:::bucketname"]
},
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": [
"arn:aws:s3:::bucketname/firstlevel",
"arn:aws:s3:::bucketname/firstlevel/*"
]
},
{
"Effect": "Allow",
"Action": ["s3:*"],
"Resource": [
"arn:aws:s3:::bucketname/firstlevel/secondlevel*",
"arn:aws:s3:::bucketname/firstlevel/secondlevel/*"
]
}
]
}

View File

@@ -32,6 +32,8 @@ remove_users() {
mc admin user remove minio conditions-2-$TIMESTAMP
mc admin user remove minio conditions-3-$TIMESTAMP
mc admin user remove minio conditions-4-$TIMESTAMP
mc admin user remove minio rewind-allowed-$TIMESTAMP
mc admin user remove minio rewind-not-allowed-$TIMESTAMP
}
remove_policies() {
@@ -58,6 +60,8 @@ remove_policies() {
mc admin policy remove minio conditions-policy-2-$TIMESTAMP
mc admin policy remove minio conditions-policy-3-$TIMESTAMP
mc admin policy remove minio conditions-policy-4-$TIMESTAMP
mc admin policy remove minio rewind-allowed-$TIMESTAMP
mc admin policy remove minio rewind-not-allowed-$TIMESTAMP
}
__init__() {

View File

@@ -47,6 +47,8 @@ create_policies() {
mc admin policy create minio conditions-policy-2-$TIMESTAMP web-app/tests/policies/conditionsPolicy2.json
mc admin policy create minio conditions-policy-3-$TIMESTAMP web-app/tests/policies/conditionsPolicy3.json
mc admin policy create minio conditions-policy-4-$TIMESTAMP web-app/tests/policies/conditionsPolicy4.json
mc admin policy create minio rewind-allowed-$TIMESTAMP web-app/tests/policies/rewind-allowed.json
mc admin policy create minio rewind-not-allowed-$TIMESTAMP web-app/tests/policies/rewind-not-allowed.json
}
create_users() {
@@ -78,6 +80,8 @@ create_users() {
mc admin user add minio conditions-2-$TIMESTAMP conditions1234
mc admin user add minio conditions-3-$TIMESTAMP conditions1234
mc admin user add minio conditions-4-$TIMESTAMP conditions1234
mc admin user add minio rewind-allowed-$TIMESTAMP rewindallowed1234
mc admin user add minio rewind-not-allowed-$TIMESTAMP rewindnotallowed1234
}
create_buckets() {
@@ -114,4 +118,6 @@ assign_policies() {
mc admin policy attach minio conditions-policy-2-$TIMESTAMP --user conditions-2-$TIMESTAMP
mc admin policy attach minio conditions-policy-3-$TIMESTAMP --user conditions-3-$TIMESTAMP
mc admin policy attach minio conditions-policy-4-$TIMESTAMP --user conditions-4-$TIMESTAMP
mc admin policy attach minio rewind-allowed-$TIMESTAMP --user rewind-allowed-$TIMESTAMP
mc admin policy attach minio rewind-not-allowed-$TIMESTAMP --user rewind-not-allowed-$TIMESTAMP
}

View File

@@ -294,3 +294,25 @@ export const conditions4 = Role(
},
{ preserveUrl: true },
);
export const rewindEnabled = Role(
loginUrl,
async (t) => {
await t
.typeText("#accessKey", "rewind-allowed-" + unixTimestamp)
.typeText("#secretKey", "rewindallowed1234")
.click(submitButton);
},
{ preserveUrl: true },
);
export const rewindNotEnabled = Role(
loginUrl,
async (t) => {
await t
.typeText("#accessKey", "rewind-not-allowed-" + unixTimestamp)
.typeText("#secretKey", "rewindnotallowed1234")
.click(submitButton);
},
{ preserveUrl: true },
);