fix: Fix system_reader role operation permission bug

1. Fix system_reader role has operation permissions on administrator page
2. Mark TODO of supported system scope roles

Change-Id: Icd697e0b5238a25307c3d24fc6742600f892b547
This commit is contained in:
Jingwei.Zhang 2021-08-19 12:58:31 +08:00
parent ad94bb6345
commit 34c13a2dcb
11 changed files with 94 additions and 40 deletions

View File

@ -12,17 +12,26 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import checkItemPolicy from 'resources/policy'; import checkItemPolicy, { systemRoleIsReader } from 'resources/policy';
export async function checkAllowed( export async function checkAllowed({
item, item,
policy, policy,
allowed, allowed,
containerProps, containerProps,
actionName, actionName,
extra extra,
) { isAdminPage,
const policyResult = checkItemPolicy(policy, item, actionName, extra); action,
}) {
const { enableSystemReader } = action || {};
const policyResult = checkItemPolicy({
policy,
item,
actionName,
isAdminPage,
enableSystemReader,
});
if (!policyResult) { if (!policyResult) {
return false; return false;
} }
@ -36,32 +45,38 @@ export async function checkAllowed(
return result; return result;
} }
export async function getAllowedResults( export async function getAllowedResults({
actions, actions,
data, data,
key, key,
containerProps, containerProps,
extra extra,
) { isAdminPage,
}) {
const allowedPromises = actions.map(async (it) => { const allowedPromises = actions.map(async (it) => {
const result = checkAllowed( const result = checkAllowed({
data, item: data,
key ? it[key].policy : it.policy, policy: key ? it[key].policy : it.policy,
key ? it[key].allowed : it.allowed, allowed: key ? it[key].allowed : it.allowed,
containerProps, containerProps,
key ? it[key].title : it.title, actionName: key ? it[key].title : it.title,
extra extra,
); isAdminPage,
action: it.action,
});
return result; return result;
}); });
const results = await Promise.all(allowedPromises); const results = await Promise.all(allowedPromises);
return results; return results;
} }
export function getPolicyResults(actions, extra) { export function getPolicyResults({ actions, extra, isAdminPage }) {
return actions.map((it) => { return actions.map((it) => {
const { policy, title } = it; const { policy, title, enableSystemReader } = it;
const result = checkItemPolicy(policy, null, title, extra); if (isAdminPage && !enableSystemReader && systemRoleIsReader()) {
return false;
}
const result = checkItemPolicy({ policy, actionName: title, extra });
return result; return result;
}); });
} }
@ -76,10 +91,10 @@ export function getAction(action, item, containerProps) {
return action; return action;
} }
export function getActionsByPolicy(actions, containerProps) { export function getActionsByPolicy({ actions, containerProps, isAdminPage }) {
const actionList = actions.map((action) => const actionList = actions.map((action) =>
getAction(action, null, containerProps) getAction(action, null, containerProps)
); );
const policyResults = getPolicyResults(actionList); const policyResults = getPolicyResults({ actions: actionList, isAdminPage });
return actionList.filter((it, index) => policyResults[index]); return actionList.filter((it, index) => policyResults[index]);
} }

View File

@ -96,12 +96,17 @@ export default function TableBatchButtons(props) {
onClickAction, onClickAction,
onCancelAction, onCancelAction,
resourceName, resourceName,
isAdminPage,
} = props; } = props;
let moreButton = null; let moreButton = null;
let batchButtons = null; let batchButtons = null;
let showedActions = []; let showedActions = [];
let restActions = []; let restActions = [];
const actionList = getActionsByPolicy(batchActions, containerProps); const actionList = getActionsByPolicy({
actions: batchActions,
containerProps,
isAdminPage,
});
if (visibleButtonNumber < actionList.length) { if (visibleButtonNumber < actionList.length) {
if (visibleButtonNumber < 0) { if (visibleButtonNumber < 0) {
restActions = actionList; restActions = actionList;

View File

@ -288,7 +288,7 @@ export default class ItemActionButtons extends Component {
} }
async updateResult(item, containerProps) { async updateResult(item, containerProps) {
const { actions } = this.props; const { actions, isAdminPage } = this.props;
const { actionList, firstAction, moreActions } = getActionList( const { actionList, firstAction, moreActions } = getActionList(
actions, actions,
item, item,
@ -297,12 +297,13 @@ export default class ItemActionButtons extends Component {
this.actionList = actionList; this.actionList = actionList;
this.firstAction = firstAction; this.firstAction = firstAction;
this.moreActions = moreActions; this.moreActions = moreActions;
const results = await getAllowedResults( const results = await getAllowedResults({
this.actionList, actions: this.actionList,
item, data: item,
'action', key: 'action',
containerProps containerProps,
); isAdminPage,
});
this.setState({ this.setState({
results, results,
}); });

View File

@ -62,15 +62,16 @@ export default class TablePrimaryButtons extends Component {
} }
async getActionsAllowed() { async getActionsAllowed() {
const { containerProps, primaryActionsExtra } = this.props; const { containerProps, primaryActionsExtra, isAdminPage } = this.props;
const { detail = null } = containerProps; const { detail = null } = containerProps;
const results = await getAllowedResults( const results = await getAllowedResults({
this.actionList, actions: this.actionList,
detail, data: detail,
null,
containerProps, containerProps,
primaryActionsExtra key: null,
); extra: primaryActionsExtra,
isAdminPage,
});
this.setState({ this.setState({
primaryAllowedResults: results, primaryAllowedResults: results,
}); });

View File

@ -110,6 +110,7 @@ export default class BaseTable extends React.Component {
hideTotal: false, hideTotal: false,
hideDownload: false, hideDownload: false,
primaryActionsExtra: null, primaryActionsExtra: null,
isAdminPage: false,
}; };
constructor(props) { constructor(props) {
@ -472,6 +473,7 @@ export default class BaseTable extends React.Component {
onClickAction, onClickAction,
onFinishAction, onFinishAction,
onCancelAction, onCancelAction,
isAdminPage,
} = this.props; } = this.props;
const { hideRow } = this.state; const { hideRow } = this.state;
const currentColumns = columns const currentColumns = columns
@ -489,6 +491,7 @@ export default class BaseTable extends React.Component {
width: 150, width: 150,
render: (text, record, index) => ( render: (text, record, index) => (
<ItemActionButtons <ItemActionButtons
isAdminPage={isAdminPage}
actions={this.itemActions} actions={this.itemActions}
onFinishAction={onFinishAction} onFinishAction={onFinishAction}
onCancelAction={onCancelAction} onCancelAction={onCancelAction}
@ -533,6 +536,7 @@ export default class BaseTable extends React.Component {
onFinishAction, onFinishAction,
onCancelAction, onCancelAction,
resourceName, resourceName,
isAdminPage,
} = this.props; } = this.props;
const selectedItems = data.filter( const selectedItems = data.filter(
(it) => selectedRowKeys.indexOf(it[rowKey]) >= 0 (it) => selectedRowKeys.indexOf(it[rowKey]) >= 0
@ -540,6 +544,7 @@ export default class BaseTable extends React.Component {
if (batchActions) { if (batchActions) {
return ( return (
<BatchActionButtons <BatchActionButtons
isAdminPage={isAdminPage}
visibleButtonNumber={3} visibleButtonNumber={3}
selectedItemKeys={selectedRowKeys} selectedItemKeys={selectedRowKeys}
selectedItems={selectedItems} selectedItems={selectedItems}
@ -639,6 +644,7 @@ export default class BaseTable extends React.Component {
renderActions() { renderActions() {
const { const {
isAdminPage,
primaryActions, primaryActions,
containerProps, containerProps,
onClickAction, onClickAction,
@ -649,6 +655,7 @@ export default class BaseTable extends React.Component {
if (primaryActions) { if (primaryActions) {
return ( return (
<PrimaryActionButtons <PrimaryActionButtons
isAdminPage={isAdminPage}
primaryActions={primaryActions} primaryActions={primaryActions}
containerProps={containerProps} containerProps={containerProps}
onClickAction={onClickAction} onClickAction={onClickAction}

View File

@ -486,7 +486,7 @@ export default class BaseList extends React.Component {
if (this.endpointError) { if (this.endpointError) {
return; return;
} }
if (!checkItemPolicy(this.policy, null, this.name)) { if (!checkItemPolicy({ policy: this.policy, actionName: this.name })) {
const error = { const error = {
message: t("You don't have access to get {name}.", { message: t("You don't have access to get {name}.", {
name: this.name.toLowerCase(), name: this.name.toLowerCase(),
@ -988,6 +988,7 @@ export default class BaseList extends React.Component {
hideTotal={this.hideTotal} hideTotal={this.hideTotal}
hideDownload={this.hideDownload} hideDownload={this.hideDownload}
primaryActionsExtra={this.primaryActionsExtra} primaryActionsExtra={this.primaryActionsExtra}
isAdminPage={this.isAdminPage}
{...this.getEnabledTableProps()} {...this.getEnabledTableProps()}
/> />
); );

View File

@ -218,7 +218,7 @@ export default class DetailBase extends React.Component {
getRouteProps = () => ({}); getRouteProps = () => ({});
fetchDataWithPolicy = (silent, params) => { fetchDataWithPolicy = (silent, params) => {
if (!checkItemPolicy(this.policy, null, this.name)) { if (!checkItemPolicy({ policy: this.policy, actionName: this.name })) {
const error = { const error = {
message: t("You don't have access to get {name}.", { message: t("You don't have access to get {name}.", {
name: this.name.toLowerCase(), name: this.name.toLowerCase(),
@ -396,6 +396,7 @@ export default class DetailBase extends React.Component {
onFinishAction={this.onFinishAction} onFinishAction={this.onFinishAction}
item={this.getActionData()} item={this.getActionData()}
containerProps={{ isAdminPage: this.isAdminPage }} containerProps={{ isAdminPage: this.isAdminPage }}
isAdminPage={this.isAdminPage}
// firstActionClassName={styles['attach-btn']} // firstActionClassName={styles['attach-btn']}
/> />
); );

View File

@ -97,7 +97,7 @@ class BaseLayout extends Component {
if (licenseKey && !this.checkLicenseKey(licenseKey)) { if (licenseKey && !this.checkLicenseKey(licenseKey)) {
return null; return null;
} }
if (policy && !checkItemPolicy(policy)) { if (policy && !checkItemPolicy({ policy })) {
return null; return null;
} }
if (children.length === 0) { if (children.length === 0) {

View File

@ -31,6 +31,8 @@ export default class View extends ModalAction {
static readOnly = true; static readOnly = true;
static enableSystemReader = true;
get name() { get name() {
return t('View'); return t('View');
} }

View File

@ -36,11 +36,32 @@ const checkPolicyRules = (rules, every, actionName) => {
return rules.some((rule) => checkPolicyRule(rule, actionName)); return rules.some((rule) => checkPolicyRule(rule, actionName));
}; };
const checkItemPolicy = (policy, item, actionName) => { export const systemRoleIsReader = () => {
const { user: { roles = [] } = {} } = globals || {};
const readerRole = 'system_reader';
const adminRoles = ['system_admin', 'admin'];
const hasReaderRole = roles.some((it) => it.name === readerRole);
if (!hasReaderRole) {
return false;
}
const hasAdminRole = roles.some((it) => adminRoles.includes(it.name));
return hasReaderRole && !hasAdminRole;
};
const checkItemPolicy = ({
policy,
item,
actionName,
isAdminPage,
enableSystemReader,
}) => {
if (globals.policies.length === 0) { if (globals.policies.length === 0) {
// TODO: change to false // TODO: change to false
return true; return true;
} }
if (isAdminPage && !enableSystemReader && systemRoleIsReader()) {
return false;
}
if (!policy) { if (!policy) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('has no policy', policy, item, actionName); console.log('has no policy', policy, item, actionName);

View File

@ -121,7 +121,7 @@ class RootStore {
this.roles = roles; this.roles = roles;
this.baseRoles = base_roles; this.baseRoles = base_roles;
this.baseDomains = base_domains; this.baseDomains = base_domains;
// const adminRole = roles.find(it => it.name === 'admin'); // TODO: fix system/project admin/member/reader for W
this.hasAdminRole = checkPolicy(onlyAdminCanReadPolicy); this.hasAdminRole = checkPolicy(onlyAdminCanReadPolicy);
globals.user.hasAdminRole = this.hasAdminRole; globals.user.hasAdminRole = this.hasAdminRole;
} }