Created Add Policy screen (#1896)

This commit is contained in:
jinapurapu
2022-04-22 21:21:06 -07:00
committed by GitHub
parent 74d4c4a3e6
commit fda090f7dd
5 changed files with 358 additions and 21 deletions

View File

@@ -127,6 +127,7 @@ export const IAM_PAGES = {
ACCOUNT_ADD: "/identity/new-account",
/* Access */
POLICIES: "/access/policies",
POLICY_ADD: "/access/add-policy",
POLICIES_VIEW: "/access/policies/*",
/* Monitoring */
TOOLS_LOGS: "/tools/logs",
@@ -329,6 +330,9 @@ export const IAM_PAGES_PERMISSIONS = {
IAM_SCOPES.ADMIN_LIST_USER_POLICIES, // displays policies
IAM_SCOPES.ADMIN_CREATE_POLICY, // displays create policy button
],
[IAM_PAGES.POLICY_ADD]: [
IAM_SCOPES.ADMIN_CREATE_POLICY, // displays create policy button
],
[IAM_PAGES.SETTINGS]: [
IAM_SCOPES.ADMIN_CONFIG_UPDATE, // displays configuration list
],

View File

@@ -102,6 +102,8 @@ const ObjectManager = React.lazy(
const Buckets = React.lazy(() => import("./Buckets/Buckets"));
const Policies = React.lazy(() => import("./Policies/Policies"));
const AddPolicy = React.lazy(() => import("./Policies/AddPolicyScreen"));
const Dashboard = React.lazy(() => import("./Dashboard/Dashboard"));
const Account = React.lazy(() => import("./Account/Account"));
@@ -304,6 +306,10 @@ const Console = ({
component: Policies,
path: IAM_PAGES.POLICIES_VIEW,
},
{
component: AddPolicy,
path: IAM_PAGES.POLICY_ADD,
},
{
component: Policies,
path: IAM_PAGES.POLICIES,

View File

@@ -0,0 +1,105 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import { Box } from "@mui/material";
import {
HelpIconFilled,
IAMPoliciesIcon,
} from "../../../icons";
const FeatureItem = ({
icon,
description,
}: {
icon: any;
description: string;
}) => {
return (
<Box
sx={{
display: "flex",
"& .min-icon": {
marginRight: "10px",
height: "23px",
width: "23px",
marginBottom: "10px",
},
}}
>
{icon}{" "}
<div style={{ fontSize: "14px", fontStyle: "italic", color: "#5E5E5E" }}>
{description}
</div>
</Box>
);
};
const AddPolicyHelpBox = ({ hasMargin = true }: { hasMargin?: boolean }) => {
return (
<Box
sx={{
flex: 1,
border: "1px solid #eaeaea",
borderRadius: "2px",
display: "flex",
flexFlow: "column",
padding: "20px",
marginLeft: {
xs: "0px",
sm: "0px",
md: hasMargin ? "30px" : "",
},
marginTop: {
xs: "0px",
},
}}
>
<Box
sx={{
fontSize: "16px",
fontWeight: 600,
display: "flex",
alignItems: "center",
marginBottom: "16px",
paddingBottom: "20px",
"& .min-icon": {
height: "21px",
width: "21px",
marginRight: "15px",
},
}}
>
<HelpIconFilled />
<div>Learn more about Policies</div>
</Box>
<Box sx={{ fontSize: "14px", marginBottom: "15px" }}>
<Box sx={{paddingBottom: "20px"}}>
<FeatureItem icon={<IAMPoliciesIcon />} description={`Create Policies`} />
<Box sx={{ paddingTop: "20px"}}>
MinIO uses Policy-Based Access Control (PBAC) to define the authorized actions and resources to which an authenticated user has access. Each policy describes one or more actions and conditions that outline the permissions of a user or group of users. </Box>
</Box>
<Box sx={{paddingBottom: "20px"}}>
MinIO PBAC is built for compatibility with AWS IAM policy syntax, structure, and behavior.
</Box>
<Box sx={{paddingBottom: "20px"}}>
Each user can access only those resources and operations which are explicitly granted by the built-in role. MinIO denies access to any other resource or action by default.
</Box>
</Box>
</Box>
);
};
export default AddPolicyHelpBox;

View File

@@ -0,0 +1,242 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { Fragment, useState } from "react";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import {
formFieldStyles,
modalStyleUtils,
} from "../Common/FormComponents/common/styleLibrary";
import Grid from "@mui/material/Grid";
import { Button, Box} from "@mui/material";
import PageHeader from "../Common/PageHeader/PageHeader";
import history from "../../../../src/history";
import PageLayout from "../Common/Layout/PageLayout";
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import AddPolicyHelpBox from "./AddPolicyHelpBox";
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
import BackLink from "../../../common/BackLink";
import { connect } from "react-redux";
import { AddAccessRuleIcon } from "../../../icons";
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
import { ErrorResponseHandler } from "../../../../src/common/types";
import api from "../../../../src/common/api";
import { setErrorSnackMessage } from "../../../../src/actions";
interface IAddPolicyProps {
classes: any;
setErrorSnackMessage: typeof setErrorSnackMessage;
}
const styles = (theme: Theme) =>
createStyles({
buttonContainer: {
textAlign: "right",
},
bottomContainer: {
display: "flex",
flexGrow: 1,
alignItems: "center",
margin: "auto",
justifyContent: "center",
"& div": {
width: 150,
"@media (max-width: 900px)": {
flexFlow: "column",
},
},
},
factorElements: {
display: "flex",
justifyContent: "flex-start",
marginLeft: 30,
},
sizeNumber: {
fontSize: 35,
fontWeight: 700,
textAlign: "center",
},
sizeDescription: {
fontSize: 14,
color: "#777",
textAlign: "center",
},
pageBox: {
border: "1px solid #EAEAEA",
borderTop: 0,
},
addPoolTitle: {
border: "1px solid #EAEAEA",
borderBottom: 0,
},
headTitle: {
fontWeight: "bold",
fontSize: 20,
paddingLeft: 20,
paddingBottom: 40,
paddingTop: 8,
textAlign: "end",
},
headIcon: {
fontWeight: "bold",
size: "50",
},
...formFieldStyles,
...modalStyleUtils,
});
const AddPolicyScreen = ({
classes,
setErrorSnackMessage,
}: IAddPolicyProps) => {
const [addLoading, setAddLoading] = useState<boolean>(false);
const [policyName, setPolicyName] = useState<string>("");
const [policyDefinition, setPolicyDefinition] = useState<string>("");
const addRecord = (event: React.FormEvent) => {
event.preventDefault();
if (addLoading) {
return;
}
setAddLoading(true);
api
.invoke("POST", "/api/v1/policies", {
name: policyName,
policy: policyDefinition,
})
.then((res) => {
setAddLoading(false);
history.push(`${IAM_PAGES.POLICIES}`);
})
.catch((err: ErrorResponseHandler) => {
setAddLoading(false);
setErrorSnackMessage(err);
});
};
const resetForm = () => {
setPolicyName("");
setPolicyDefinition("");
};
const validSave = policyName.trim() !== "";
return (
<Fragment>
<Grid item xs={12}>
<PageHeader
label={<BackLink to={IAM_PAGES.POLICIES} label={"Policies"} />}
/>
<PageLayout>
<Grid
item
xs={12}
container
className={classes.title}
align-items="stretch"
>
<Grid item className={classes.headIcon}>
<AddAccessRuleIcon />
</Grid>
<Grid item className={classes.headTitle}>
Create Policy
</Grid>
</Grid>
<Grid container align-items="center">
<Grid item xs={8}>
<Box>
<form noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
addRecord(e);
}}>
<Grid container item spacing = "20">
<Grid item xs={12} >
<Grid container>
<Grid item xs={12} className={classes.formFieldRow}>
<InputBoxWrapper
id="policy-name"
name="policy-name"
label="Policy Name"
autoFocus={true}
value={policyName}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPolicyName(e.target.value);
}}
/>
</Grid>
<Grid item xs={12} className={classes.userSelector}>
<CodeMirrorWrapper
label={"Write Policy"}
value={policyDefinition}
onBeforeChange={(editor, data, value) => {
setPolicyDefinition(value);
}}
editorHeight={"350px"}
/>
</Grid>
</Grid>
<Grid item xs={12} className={classes.modalButtonBar}>
<Button
type="button"
variant="outlined"
color="primary"
className={classes.spacerRight}
onClick={resetForm}
>
Clear
</Button>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading || !validSave}
>
Save
</Button>
</Grid>
</Grid>
</Grid>
</form>
</Box>
</Grid>
<Grid item xs={4}>
<Box>
<AddPolicyHelpBox />
</Box>
</Grid>
</Grid>
</PageLayout>
</Grid>
</Fragment>
);
};
const mapDispatchToProps = {
setErrorSnackMessage,
};
const connector = connect(null, mapDispatchToProps);
export default withStyles(styles)(connector(AddPolicyScreen));

View File

@@ -51,7 +51,6 @@ import SearchBox from "../Common/SearchBox";
import withSuspense from "../Common/Components/withSuspense";
import RBIconButton from "../Buckets/BucketDetails/SummaryItems/RBIconButton";
const AddPolicy = withSuspense(React.lazy(() => import("./AddPolicy")));
const DeletePolicy = withSuspense(React.lazy(() => import("./DeletePolicy")));
const styles = (theme: Theme) =>
@@ -73,12 +72,9 @@ interface IPoliciesProps {
const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
const [records, setRecords] = useState<Policy[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [addScreenOpen, setAddScreenOpen] = useState<boolean>(false);
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
const [selectedPolicy, setSelectedPolicy] = useState<string>("");
const [filterPolicies, setFilterPolicies] = useState<string>("");
const [policyEdit, setPolicyEdit] = useState<any>(null);
const viewPolicy = hasPermission(CONSOLE_UI_RESOURCE, [
IAM_SCOPES.ADMIN_GET_POLICY,
]);
@@ -132,14 +128,6 @@ const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
setLoading(true);
};
const closeAddModalAndRefresh = (refresh: boolean) => {
setAddScreenOpen(false);
if (refresh) {
fetchRecords();
}
};
const closeDeleteModalAndRefresh = (refresh: boolean) => {
setDeleteOpen(false);
@@ -177,13 +165,6 @@ const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
return (
<React.Fragment>
{addScreenOpen && (
<AddPolicy
open={addScreenOpen}
closeModalAndRefresh={closeAddModalAndRefresh}
policyEdit={policyEdit}
/>
)}
{deleteOpen && (
<DeletePolicy
deleteOpen={deleteOpen}
@@ -214,8 +195,7 @@ const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
color="primary"
icon={<AddIcon />}
onClick={() => {
setAddScreenOpen(true);
setPolicyEdit(null);
history.push(`${IAM_PAGES.POLICY_ADD}`);
}}
/>
</SecureComponent>