Service account policy UI (#1519)

* saving

* service account policy UI

* fixing warning

* Update portal-ui/src/screens/Console/Account/ServiceAccountPolicy.tsx

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>

* fixing comment

Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
Co-authored-by: Lenin Alevski <alevsk.8772@gmail.com>
This commit is contained in:
adfost
2022-02-08 22:52:55 -08:00
committed by GitHub
parent 7e8441264f
commit 75b3082172
3 changed files with 157 additions and 1 deletions

View File

@@ -51,8 +51,9 @@ import {
} from "../../../common/SecureComponent/permissions";
import SecureComponent from "../../../common/SecureComponent/SecureComponent";
import RBIconButton from "../Buckets/BucketDetails/SummaryItems/RBIconButton";
import { selectSAs } from "../../Console/Configurations/utils";
import { selectSAs } from "../Configurations/utils";
import DeleteMultipleServiceAccounts from "../Users/DeleteMultipleServiceAccounts";
import ServiceAccountPolicy from "./ServiceAccountPolicy";
const AddServiceAccount = withSuspense(
React.lazy(() => import("./AddServiceAccount"))
@@ -98,6 +99,7 @@ const Account = ({ classes, displayErrorMessage }: IServiceAccountsProps) => {
useState<boolean>(false);
const [selectedSAs, setSelectedSAs] = useState<string[]>([]);
const [deleteMultipleOpen, setDeleteMultipleOpen] = useState<boolean>(false);
const [policyOpen, setPolicyOpen] = useState<boolean>(false);
useEffect(() => {
fetchRecords();
@@ -157,6 +159,11 @@ const Account = ({ classes, displayErrorMessage }: IServiceAccountsProps) => {
}
};
const policyModalOpen = (selectedServiceAccount: string) => {
setSelectedServiceAccount(selectedServiceAccount);
setPolicyOpen(true);
};
const selectAllItems = () => {
if (selectedSAs.length === records.length) {
setSelectedSAs([]);
@@ -170,12 +177,17 @@ const Account = ({ classes, displayErrorMessage }: IServiceAccountsProps) => {
setNewServiceAccount(null);
};
const closePolicyModal = () => {
setPolicyOpen(false);
};
const confirmDeleteServiceAccount = (selectedServiceAccount: string) => {
setSelectedServiceAccount(selectedServiceAccount);
setDeleteOpen(true);
};
const tableActions = [
{ type: "view", onClick: policyModalOpen },
{ type: "delete", onClick: confirmDeleteServiceAccount },
];
@@ -219,6 +231,13 @@ const Account = ({ classes, displayErrorMessage }: IServiceAccountsProps) => {
entity="Service Account"
/>
)}
{policyOpen && (
<ServiceAccountPolicy
open={policyOpen}
selectedAccessKey={selectedServiceAccount}
closeModalAndRefresh={closePolicyModal}
/>
)}
<ChangePasswordModal
open={changePasswordModalOpen}
closeModal={() => setChangePasswordModalOpen(false)}

View File

@@ -0,0 +1,131 @@
// 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, { useEffect, useState } from "react";
import { connect } from "react-redux";
import { Button } from "@mui/material";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import Grid from "@mui/material/Grid";
import {
formFieldStyles,
modalStyleUtils,
spacingUtils,
} from "../Common/FormComponents/common/styleLibrary";
import { setModalErrorSnackMessage } from "../../../actions";
import { ErrorResponseHandler } from "../../../common/types";
import api from "../../../common/api";
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
import { ChangeAccessPolicyIcon } from "../../../icons";
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
const styles = (theme: Theme) =>
createStyles({
codeMirrorContainer: {
marginBottom: 20,
"& label": {
marginBottom: ".5rem",
},
"& label + div": {
display: "none",
},
},
...formFieldStyles,
...modalStyleUtils,
...spacingUtils,
});
createStyles({
...modalStyleUtils,
...spacingUtils,
});
interface IServiceAccountPolicyProps {
classes: any;
open: boolean;
selectedAccessKey: string | null;
closeModalAndRefresh: () => void;
setModalErrorSnackMessage: typeof setModalErrorSnackMessage;
}
const ServiceAccountPolicy = ({
classes,
open,
selectedAccessKey,
closeModalAndRefresh,
setModalErrorSnackMessage,
}: IServiceAccountPolicyProps) => {
const [loading, setLoading] = useState<boolean>(true);
const [policyDefinition, setPolicyDefinition] = useState<string>("");
useEffect(() => {
if (loading) {
api
.invoke("GET", `/api/v1/service-accounts/${selectedAccessKey}/policy`)
.then((res) => {
setLoading(false);
setPolicyDefinition(res);
})
.catch((err: ErrorResponseHandler) => {
setLoading(false);
setModalErrorSnackMessage(err);
});
}
}, [loading, setLoading, setModalErrorSnackMessage, selectedAccessKey]);
return (
<ModalWrapper
title="Service Account Policy"
modalOpen={open}
onClose={() => {
closeModalAndRefresh();
}}
titleIcon={<ChangeAccessPolicyIcon />}
>
<Grid container>
<Grid item xs={12} className={classes.codeMirrorContainer}>
<CodeMirrorWrapper
label={`Service Account Policy`}
value={policyDefinition}
onBeforeChange={(editor, data, value) => {
setPolicyDefinition(value);
}}
editorHeight={"350px"}
readOnly={true}
/>
</Grid>
<Grid item xs={12} className={classes.modalButtonBar}>
<Button
type="button"
variant="outlined"
color="primary"
onClick={() => {
closeModalAndRefresh();
}}
disabled={loading}
>
Cancel
</Button>
</Grid>
</Grid>
</ModalWrapper>
);
};
const connector = connect(null, {
setModalErrorSnackMessage,
});
export default withStyles(styles)(connector(ServiceAccountPolicy));

View File

@@ -19,6 +19,7 @@ package restapi
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"strings"
@@ -366,6 +367,11 @@ func getServiceAccountPolicy(ctx context.Context, userClient MinioAdmin, accessK
if err != nil {
return "", err
}
var policy iampolicy.Policy
json.Unmarshal([]byte(serviceAccountInfo.Policy), &policy)
if policy.Statements == nil {
return "", nil
}
return serviceAccountInfo.Policy, nil
}