github.com/minio/console@v1.4.1/web-app/src/screens/Console/Buckets/BucketDetails/AccessDetailsPanel.tsx (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2021 MinIO, Inc.
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // This program is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  // GNU Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  import React, { Fragment, useEffect, useState } from "react";
    18  import { useSelector } from "react-redux";
    19  import { useNavigate, useParams } from "react-router-dom";
    20  import { DataTable, SectionTitle, Tabs, HelpTip } from "mds";
    21  import { api } from "api";
    22  import { errorToHandler } from "api/errors";
    23  import {
    24    CONSOLE_UI_RESOURCE,
    25    IAM_PAGES,
    26    IAM_SCOPES,
    27  } from "../../../../common/SecureComponent/permissions";
    28  import {
    29    hasPermission,
    30    SecureComponent,
    31  } from "../../../../common/SecureComponent";
    32  import { encodeURLString } from "../../../../common/utils";
    33  import { setErrorSnackMessage, setHelpName } from "../../../../systemSlice";
    34  import { selBucketDetailsLoading } from "./bucketDetailsSlice";
    35  import { useAppDispatch } from "../../../../store";
    36  import { Policy } from "../../../../api/consoleApi";
    37  
    38  const AccessDetails = () => {
    39    const dispatch = useAppDispatch();
    40    const navigate = useNavigate();
    41    const params = useParams();
    42  
    43    const loadingBucket = useSelector(selBucketDetailsLoading);
    44  
    45    const [curTab, setCurTab] = useState<string>("simple-tab-0");
    46    const [loadingPolicies, setLoadingPolicies] = useState<boolean>(true);
    47    const [bucketPolicy, setBucketPolicy] = useState<Policy[] | undefined>([]);
    48    const [loadingUsers, setLoadingUsers] = useState<boolean>(true);
    49    const [bucketUsers, setBucketUsers] = useState<string[]>([]);
    50  
    51    const bucketName = params.bucketName || "";
    52  
    53    const displayPoliciesList = hasPermission(bucketName, [
    54      IAM_SCOPES.ADMIN_LIST_USER_POLICIES,
    55    ]);
    56  
    57    const displayUsersList = hasPermission(
    58      bucketName,
    59      [
    60        IAM_SCOPES.ADMIN_GET_POLICY,
    61        IAM_SCOPES.ADMIN_LIST_USERS,
    62        IAM_SCOPES.ADMIN_LIST_GROUPS,
    63      ],
    64      true,
    65    );
    66  
    67    const viewUser = hasPermission(CONSOLE_UI_RESOURCE, [
    68      IAM_SCOPES.ADMIN_GET_USER,
    69    ]);
    70    const viewPolicy = hasPermission(CONSOLE_UI_RESOURCE, [
    71      IAM_SCOPES.ADMIN_GET_POLICY,
    72      IAM_SCOPES.ADMIN_LIST_USERS,
    73      IAM_SCOPES.ADMIN_LIST_GROUPS,
    74    ]);
    75  
    76    useEffect(() => {
    77      if (loadingBucket) {
    78        setLoadingUsers(true);
    79        setLoadingPolicies(true);
    80      }
    81    }, [loadingBucket, setLoadingUsers, setLoadingPolicies]);
    82  
    83    const PolicyActions = [
    84      {
    85        type: "view",
    86        disableButtonFunction: () => !viewPolicy,
    87        onClick: (policy: any) => {
    88          navigate(`${IAM_PAGES.POLICIES}/${encodeURLString(policy.name)}`);
    89        },
    90      },
    91    ];
    92  
    93    const userTableActions = [
    94      {
    95        type: "view",
    96        disableButtonFunction: () => !viewUser,
    97        onClick: (user: any) => {
    98          navigate(`${IAM_PAGES.USERS}/${encodeURLString(user)}`);
    99        },
   100      },
   101    ];
   102  
   103    useEffect(() => {
   104      if (loadingUsers) {
   105        if (displayUsersList) {
   106          api.bucketUsers
   107            .listUsersWithAccessToBucket(bucketName)
   108            .then((res) => {
   109              setBucketUsers(res.data);
   110              setLoadingUsers(false);
   111            })
   112            .catch((err) => {
   113              dispatch(setErrorSnackMessage(errorToHandler(err)));
   114              setLoadingUsers(false);
   115            });
   116        } else {
   117          setLoadingUsers(false);
   118        }
   119      }
   120    }, [loadingUsers, dispatch, bucketName, displayUsersList]);
   121  
   122    useEffect(() => {
   123      dispatch(setHelpName("bucket_detail_access"));
   124      // eslint-disable-next-line react-hooks/exhaustive-deps
   125    }, []);
   126  
   127    useEffect(() => {
   128      if (loadingPolicies) {
   129        if (displayPoliciesList) {
   130          api.bucketPolicy
   131            .listPoliciesWithBucket(bucketName)
   132            .then((res) => {
   133              setBucketPolicy(res.data.policies);
   134              setLoadingPolicies(false);
   135            })
   136            .catch((err) => {
   137              dispatch(setErrorSnackMessage(errorToHandler(err)));
   138              setLoadingPolicies(false);
   139            });
   140        } else {
   141          setLoadingPolicies(false);
   142        }
   143      }
   144    }, [loadingPolicies, dispatch, bucketName, displayPoliciesList]);
   145  
   146    return (
   147      <Fragment>
   148        <SectionTitle separator>
   149          <HelpTip
   150            content={
   151              <Fragment>
   152                Understand which{" "}
   153                <a
   154                  target="blank"
   155                  href="https://min.io/docs/minio/linux/administration/identity-access-management/policy-based-access-control.html#"
   156                >
   157                  Policies
   158                </a>{" "}
   159                and{" "}
   160                <a
   161                  target="blank"
   162                  href="https://min.io/docs/minio/linux/administration/identity-access-management/minio-user-management.html"
   163                >
   164                  Users
   165                </a>{" "}
   166                are authorized to access this Bucket.
   167              </Fragment>
   168            }
   169            placement="right"
   170          >
   171            Access Audit
   172          </HelpTip>
   173        </SectionTitle>
   174        <Tabs
   175          currentTabOrPath={curTab}
   176          onTabClick={(newValue: string) => {
   177            setCurTab(newValue);
   178          }}
   179          horizontal
   180          options={[
   181            {
   182              tabConfig: { label: "Policies", id: "simple-tab-0" },
   183              content: (
   184                <SecureComponent
   185                  scopes={[IAM_SCOPES.ADMIN_LIST_USER_POLICIES]}
   186                  resource={bucketName}
   187                  errorProps={{ disabled: true }}
   188                >
   189                  {bucketPolicy && (
   190                    <DataTable
   191                      noBackground={true}
   192                      itemActions={PolicyActions}
   193                      columns={[{ label: "Name", elementKey: "name" }]}
   194                      isLoading={loadingPolicies}
   195                      records={bucketPolicy}
   196                      entityName="Policies"
   197                      idField="name"
   198                    />
   199                  )}
   200                </SecureComponent>
   201              ),
   202            },
   203            {
   204              tabConfig: { label: "Users", id: "simple-tab-1" },
   205              content: (
   206                <SecureComponent
   207                  scopes={[
   208                    IAM_SCOPES.ADMIN_GET_POLICY,
   209                    IAM_SCOPES.ADMIN_LIST_USERS,
   210                    IAM_SCOPES.ADMIN_LIST_GROUPS,
   211                  ]}
   212                  resource={bucketName}
   213                  matchAll
   214                  errorProps={{ disabled: true }}
   215                >
   216                  <DataTable
   217                    noBackground={true}
   218                    itemActions={userTableActions}
   219                    columns={[{ label: "User", elementKey: "accessKey" }]}
   220                    isLoading={loadingUsers}
   221                    records={bucketUsers}
   222                    entityName="Users"
   223                    idField="accessKey"
   224                  />
   225                </SecureComponent>
   226              ),
   227            },
   228          ]}
   229        />
   230      </Fragment>
   231    );
   232  };
   233  
   234  export default AccessDetails;