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:
parent
ad94bb6345
commit
34c13a2dcb
@ -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]);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
|
@ -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}
|
||||||
|
@ -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()}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -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']}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -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) {
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user