RBAC: Remove builtin role code (#53767)

* remove rbacBuiltInRoleAssignmentEnabled from frontendsettings

* RBAC: Remove RBACBuiltInRoleAssignmentEnabled

* RBAC: Remove code for builtin role

* RolePicker: Remove unused prop

* RolePicker: Rename builtinRole to basicRole

* RolePicker: Rename onBuiltinRoleChange to onBasicRoleChange

* RolePicker: Rename properties
pull/53775/head^2
Karl Persson 3 years ago committed by GitHub
parent 8145caf554
commit 4ff4aaab23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      packages/grafana-data/src/types/config.ts
  2. 1
      packages/grafana-runtime/src/config.ts
  3. 1
      pkg/api/frontendsettings.go
  4. 9
      pkg/services/accesscontrol/accesscontrol.go
  5. 4
      pkg/services/accesscontrol/ossaccesscontrol/ossaccesscontrol.go
  6. 4
      pkg/setting/setting.go
  7. 47
      public/app/core/components/RolePicker/RolePicker.tsx
  8. 14
      public/app/core/components/RolePicker/RolePickerInput.tsx
  9. 38
      public/app/core/components/RolePicker/RolePickerMenu.tsx
  10. 4
      public/app/core/components/RolePicker/TeamRolePicker.tsx
  11. 23
      public/app/core/components/RolePicker/UserRolePicker.tsx
  12. 8
      public/app/core/components/RolePicker/api.ts
  13. 4
      public/app/core/services/context_srv.ts
  14. 16
      public/app/features/admin/UserOrgs.tsx
  15. 16
      public/app/features/serviceaccounts/ServiceAccountCreatePage.tsx
  16. 1
      public/app/features/serviceaccounts/ServiceAccountPage.test.tsx
  17. 4
      public/app/features/serviceaccounts/ServiceAccountPage.tsx
  18. 1
      public/app/features/serviceaccounts/ServiceAccountsListPage.test.tsx
  19. 2
      public/app/features/serviceaccounts/ServiceAccountsListPage.tsx
  20. 10
      public/app/features/serviceaccounts/components/ServiceAccountProfile.tsx
  21. 16
      public/app/features/serviceaccounts/components/ServiceAccountRoleRow.tsx
  22. 9
      public/app/features/serviceaccounts/components/ServiceAccountsListItem.tsx
  23. 11
      public/app/features/serviceaccounts/state/actions.ts
  24. 5
      public/app/features/serviceaccounts/state/reducers.ts
  25. 20
      public/app/features/users/UsersTable.tsx
  26. 1
      public/app/types/accessControl.ts
  27. 1
      public/app/types/serviceaccount.ts

@ -182,7 +182,6 @@ export interface GrafanaConfig {
verifyEmailEnabled: boolean; verifyEmailEnabled: boolean;
oauth: OAuthSettings; oauth: OAuthSettings;
rbacEnabled: boolean; rbacEnabled: boolean;
rbacBuiltInRoleAssignmentEnabled: boolean;
disableUserSignUp: boolean; disableUserSignUp: boolean;
loginHint: string; loginHint: string;
passwordHint: string; passwordHint: string;

@ -62,7 +62,6 @@ export class GrafanaBootConfig implements GrafanaConfig {
verifyEmailEnabled = false; verifyEmailEnabled = false;
oauth: OAuthSettings = {}; oauth: OAuthSettings = {};
rbacEnabled = true; rbacEnabled = true;
rbacBuiltInRoleAssignmentEnabled = false;
disableUserSignUp = false; disableUserSignUp = false;
loginHint = ''; loginHint = '';
passwordHint = ''; passwordHint = '';

@ -112,7 +112,6 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i
"sigV4AuthEnabled": setting.SigV4AuthEnabled, "sigV4AuthEnabled": setting.SigV4AuthEnabled,
"azureAuthEnabled": setting.AzureAuthEnabled, "azureAuthEnabled": setting.AzureAuthEnabled,
"rbacEnabled": hs.Cfg.RBACEnabled, "rbacEnabled": hs.Cfg.RBACEnabled,
"rbacBuiltInRoleAssignmentEnabled": hs.Cfg.RBACBuiltInRoleAssignmentEnabled,
"exploreEnabled": setting.ExploreEnabled, "exploreEnabled": setting.ExploreEnabled,
"helpEnabled": setting.HelpEnabled, "helpEnabled": setting.HelpEnabled,
"profileEnabled": setting.ProfileEnabled, "profileEnabled": setting.ProfileEnabled,

@ -272,16 +272,9 @@ func IsDisabled(cfg *setting.Cfg) bool {
} }
// GetOrgRoles returns legacy org roles for a user // GetOrgRoles returns legacy org roles for a user
func GetOrgRoles(cfg *setting.Cfg, user *user.SignedInUser) []string { func GetOrgRoles(user *user.SignedInUser) []string {
roles := []string{string(user.OrgRole)} roles := []string{string(user.OrgRole)}
// With built-in role simplifying, inheritance is performed upon role registration.
if cfg.RBACBuiltInRoleAssignmentEnabled {
for _, br := range user.OrgRole.Children() {
roles = append(roles, string(br))
}
}
if user.IsGrafanaAdmin { if user.IsGrafanaAdmin {
roles = append(roles, RoleGrafanaAdmin) roles = append(roles, RoleGrafanaAdmin)
} }

@ -112,7 +112,7 @@ func (ac *OSSAccessControlService) GetUserPermissions(ctx context.Context, user
dbPermissions, err := ac.store.GetUserPermissions(ctx, accesscontrol.GetUserPermissionsQuery{ dbPermissions, err := ac.store.GetUserPermissions(ctx, accesscontrol.GetUserPermissionsQuery{
OrgID: user.OrgID, OrgID: user.OrgID,
UserID: user.UserID, UserID: user.UserID,
Roles: accesscontrol.GetOrgRoles(ac.cfg, user), Roles: accesscontrol.GetOrgRoles(user),
TeamIDs: user.Teams, TeamIDs: user.Teams,
Actions: actionsToFetch, Actions: actionsToFetch,
}) })
@ -136,7 +136,7 @@ func (ac *OSSAccessControlService) GetUserPermissions(ctx context.Context, user
func (ac *OSSAccessControlService) getFixedPermissions(ctx context.Context, user *user.SignedInUser) []accesscontrol.Permission { func (ac *OSSAccessControlService) getFixedPermissions(ctx context.Context, user *user.SignedInUser) []accesscontrol.Permission {
permissions := make([]accesscontrol.Permission, 0) permissions := make([]accesscontrol.Permission, 0)
for _, builtin := range accesscontrol.GetOrgRoles(ac.cfg, user) { for _, builtin := range accesscontrol.GetOrgRoles(user) {
if basicRole, ok := ac.roles[builtin]; ok { if basicRole, ok := ac.roles[builtin]; ok {
permissions = append(permissions, basicRole.Permissions...) permissions = append(permissions, basicRole.Permissions...)
} }

@ -451,9 +451,6 @@ type Cfg struct {
// Access Control // Access Control
RBACEnabled bool RBACEnabled bool
RBACPermissionCache bool RBACPermissionCache bool
// Undocumented option as a backup in case removing builtin-role assignment
// fails
RBACBuiltInRoleAssignmentEnabled bool
} }
type CommandLineArgs struct { type CommandLineArgs struct {
@ -1356,7 +1353,6 @@ func readAccessControlSettings(iniFile *ini.File, cfg *Cfg) {
rbac := iniFile.Section("rbac") rbac := iniFile.Section("rbac")
cfg.RBACEnabled = rbac.Key("enabled").MustBool(true) cfg.RBACEnabled = rbac.Key("enabled").MustBool(true)
cfg.RBACPermissionCache = rbac.Key("permission_cache").MustBool(true) cfg.RBACPermissionCache = rbac.Key("permission_cache").MustBool(true)
cfg.RBACBuiltInRoleAssignmentEnabled = rbac.Key("builtin_role_assignment_enabled").MustBool(false)
} }
func readUserSettings(iniFile *ini.File, cfg *Cfg) error { func readUserSettings(iniFile *ini.File, cfg *Cfg) error {

@ -8,44 +8,43 @@ import { RolePickerMenu } from './RolePickerMenu';
import { MENU_MAX_HEIGHT, ROLE_PICKER_WIDTH } from './constants'; import { MENU_MAX_HEIGHT, ROLE_PICKER_WIDTH } from './constants';
export interface Props { export interface Props {
builtInRole?: OrgRole; basicRole?: OrgRole;
appliedRoles: Role[]; appliedRoles: Role[];
roleOptions: Role[]; roleOptions: Role[];
builtInRoles?: Record<string, Role[]>;
isLoading?: boolean; isLoading?: boolean;
disabled?: boolean; disabled?: boolean;
builtinRolesDisabled?: boolean; basicRoleDisabled?: boolean;
showBuiltInRole?: boolean; showBasicRole?: boolean;
onRolesChange: (newRoles: Role[]) => void; onRolesChange: (newRoles: Role[]) => void;
onBuiltinRoleChange?: (newRole: OrgRole) => void; onBasicRoleChange?: (newRole: OrgRole) => void;
canUpdateRoles?: boolean; canUpdateRoles?: boolean;
apply?: boolean; apply?: boolean;
} }
export const RolePicker = ({ export const RolePicker = ({
builtInRole, basicRole,
appliedRoles, appliedRoles,
roleOptions, roleOptions,
disabled, disabled,
isLoading, isLoading,
builtinRolesDisabled, basicRoleDisabled,
showBuiltInRole, showBasicRole,
onRolesChange, onRolesChange,
onBuiltinRoleChange, onBasicRoleChange,
canUpdateRoles = true, canUpdateRoles = true,
apply = false, apply = false,
}: Props): JSX.Element | null => { }: Props): JSX.Element | null => {
const [isOpen, setOpen] = useState(false); const [isOpen, setOpen] = useState(false);
const [selectedRoles, setSelectedRoles] = useState<Role[]>(appliedRoles); const [selectedRoles, setSelectedRoles] = useState<Role[]>(appliedRoles);
const [selectedBuiltInRole, setSelectedBuiltInRole] = useState<OrgRole | undefined>(builtInRole); const [selectedBuiltInRole, setSelectedBuiltInRole] = useState<OrgRole | undefined>(basicRole);
const [query, setQuery] = useState(''); const [query, setQuery] = useState('');
const [offset, setOffset] = useState({ vertical: 0, horizontal: 0 }); const [offset, setOffset] = useState({ vertical: 0, horizontal: 0 });
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
useEffect(() => { useEffect(() => {
setSelectedBuiltInRole(builtInRole); setSelectedBuiltInRole(basicRole);
setSelectedRoles(appliedRoles); setSelectedRoles(appliedRoles);
}, [appliedRoles, builtInRole]); }, [appliedRoles, basicRole]);
useEffect(() => { useEffect(() => {
const dimensions = ref?.current?.getBoundingClientRect(); const dimensions = ref?.current?.getBoundingClientRect();
@ -85,8 +84,8 @@ export const RolePicker = ({
setOpen(false); setOpen(false);
setQuery(''); setQuery('');
setSelectedRoles(appliedRoles); setSelectedRoles(appliedRoles);
setSelectedBuiltInRole(builtInRole); setSelectedBuiltInRole(basicRole);
}, [appliedRoles, builtInRole]); }, [appliedRoles, basicRole]);
// Only call onClose if menu is open. Prevent unnecessary calls for multiple pickers on the page. // Only call onClose if menu is open. Prevent unnecessary calls for multiple pickers on the page.
const onClickOutside = () => isOpen && onClose(); const onClickOutside = () => isOpen && onClose();
@ -103,13 +102,13 @@ export const RolePicker = ({
setSelectedRoles(roles); setSelectedRoles(roles);
}; };
const onBuiltInRoleSelect = (role: OrgRole) => { const onBasicRoleSelect = (role: OrgRole) => {
setSelectedBuiltInRole(role); setSelectedBuiltInRole(role);
}; };
const onUpdate = (newRoles: Role[], newBuiltInRole?: OrgRole) => { const onUpdate = (newRoles: Role[], newBuiltInRole?: OrgRole) => {
if (onBuiltinRoleChange && newBuiltInRole && newBuiltInRole !== builtInRole) { if (onBasicRoleChange && newBuiltInRole && newBuiltInRole !== basicRole) {
onBuiltinRoleChange(newBuiltInRole); onBasicRoleChange(newBuiltInRole);
} }
if (canUpdateRoles) { if (canUpdateRoles) {
onRolesChange(newRoles); onRolesChange(newRoles);
@ -141,7 +140,7 @@ export const RolePicker = ({
<div data-testid="role-picker" style={{ position: 'relative', width: ROLE_PICKER_WIDTH }} ref={ref}> <div data-testid="role-picker" style={{ position: 'relative', width: ROLE_PICKER_WIDTH }} ref={ref}>
<ClickOutsideWrapper onClick={onClickOutside}> <ClickOutsideWrapper onClick={onClickOutside}>
<RolePickerInput <RolePickerInput
builtInRole={selectedBuiltInRole} basicRole={selectedBuiltInRole}
appliedRoles={selectedRoles} appliedRoles={selectedRoles}
query={query} query={query}
onQueryChange={onInputChange} onQueryChange={onInputChange}
@ -149,20 +148,20 @@ export const RolePicker = ({
onClose={onClose} onClose={onClose}
isFocused={isOpen} isFocused={isOpen}
disabled={disabled} disabled={disabled}
showBuiltInRole={showBuiltInRole} showBasicRole={showBasicRole}
/> />
{isOpen && ( {isOpen && (
<RolePickerMenu <RolePickerMenu
options={getOptions()} options={getOptions()}
builtInRole={selectedBuiltInRole} basicRole={selectedBuiltInRole}
appliedRoles={appliedRoles} appliedRoles={appliedRoles}
onBuiltInRoleSelect={onBuiltInRoleSelect} onBasicRoleSelect={onBasicRoleSelect}
onSelect={onSelect} onSelect={onSelect}
onUpdate={onUpdate} onUpdate={onUpdate}
showGroups={query.length === 0 || query.trim() === ''} showGroups={query.length === 0 || query.trim() === ''}
builtinRolesDisabled={builtinRolesDisabled} basicRoleDisabled={basicRoleDisabled}
showBuiltInRole={showBuiltInRole} showBasicRole={showBasicRole}
updateDisabled={builtinRolesDisabled && !canUpdateRoles} updateDisabled={basicRoleDisabled && !canUpdateRoles}
apply={apply} apply={apply}
offset={offset} offset={offset}
/> />

@ -13,9 +13,9 @@ const stopPropagation = (event: React.MouseEvent<HTMLDivElement>) => event.stopP
interface InputProps extends HTMLProps<HTMLInputElement> { interface InputProps extends HTMLProps<HTMLInputElement> {
appliedRoles: Role[]; appliedRoles: Role[];
builtInRole?: string; basicRole?: string;
query: string; query: string;
showBuiltInRole?: boolean; showBasicRole?: boolean;
isFocused?: boolean; isFocused?: boolean;
disabled?: boolean; disabled?: boolean;
onQueryChange: (query?: string) => void; onQueryChange: (query?: string) => void;
@ -25,11 +25,11 @@ interface InputProps extends HTMLProps<HTMLInputElement> {
export const RolePickerInput = ({ export const RolePickerInput = ({
appliedRoles, appliedRoles,
builtInRole, basicRole,
disabled, disabled,
isFocused, isFocused,
query, query,
showBuiltInRole, showBasicRole,
onOpen, onOpen,
onClose, onClose,
onQueryChange, onQueryChange,
@ -53,12 +53,12 @@ export const RolePickerInput = ({
return !isFocused ? ( return !isFocused ? (
<div className={cx(styles.wrapper, styles.selectedRoles)} onMouseDown={onOpen}> <div className={cx(styles.wrapper, styles.selectedRoles)} onMouseDown={onOpen}>
{showBuiltInRole && <ValueContainer>{builtInRole}</ValueContainer>} {showBasicRole && <ValueContainer>{basicRole}</ValueContainer>}
<RolesLabel appliedRoles={appliedRoles} numberOfRoles={numberOfRoles} showBuiltInRole={showBuiltInRole} /> <RolesLabel appliedRoles={appliedRoles} numberOfRoles={numberOfRoles} showBuiltInRole={showBasicRole} />
</div> </div>
) : ( ) : (
<div className={styles.wrapper}> <div className={styles.wrapper}>
{showBuiltInRole && <ValueContainer>{builtInRole}</ValueContainer>} {showBasicRole && <ValueContainer>{basicRole}</ValueContainer>}
{appliedRoles.map((role) => ( {appliedRoles.map((role) => (
<ValueContainer key={role.uid}>{role.displayName}</ValueContainer> <ValueContainer key={role.uid}>{role.displayName}</ValueContainer>
))} ))}

@ -19,8 +19,8 @@ import { OrgRole, Role } from 'app/types';
import { MENU_MAX_HEIGHT } from './constants'; import { MENU_MAX_HEIGHT } from './constants';
const BuiltinRoles = Object.values(OrgRole); const BasicRoles = Object.values(OrgRole);
const BuiltinRoleOption: Array<SelectableValue<OrgRole>> = BuiltinRoles.map((r) => ({ const BasicRoleOption: Array<SelectableValue<OrgRole>> = BasicRoles.map((r) => ({
label: r, label: r,
value: r, value: r,
})); }));
@ -31,14 +31,14 @@ const fixedRoleGroupNames: Record<string, string> = {
}; };
interface RolePickerMenuProps { interface RolePickerMenuProps {
builtInRole?: OrgRole; basicRole?: OrgRole;
options: Role[]; options: Role[];
appliedRoles: Role[]; appliedRoles: Role[];
showGroups?: boolean; showGroups?: boolean;
builtinRolesDisabled?: boolean; basicRoleDisabled?: boolean;
showBuiltInRole?: boolean; showBasicRole?: boolean;
onSelect: (roles: Role[]) => void; onSelect: (roles: Role[]) => void;
onBuiltInRoleSelect?: (role: OrgRole) => void; onBasicRoleSelect?: (role: OrgRole) => void;
onUpdate: (newRoles: Role[], newBuiltInRole?: OrgRole) => void; onUpdate: (newRoles: Role[], newBuiltInRole?: OrgRole) => void;
updateDisabled?: boolean; updateDisabled?: boolean;
apply?: boolean; apply?: boolean;
@ -46,21 +46,21 @@ interface RolePickerMenuProps {
} }
export const RolePickerMenu = ({ export const RolePickerMenu = ({
builtInRole, basicRole,
options, options,
appliedRoles, appliedRoles,
showGroups, showGroups,
builtinRolesDisabled, basicRoleDisabled,
showBuiltInRole, showBasicRole,
onSelect, onSelect,
onBuiltInRoleSelect, onBasicRoleSelect,
onUpdate, onUpdate,
updateDisabled, updateDisabled,
offset, offset,
apply, apply,
}: RolePickerMenuProps): JSX.Element => { }: RolePickerMenuProps): JSX.Element => {
const [selectedOptions, setSelectedOptions] = useState<Role[]>(appliedRoles); const [selectedOptions, setSelectedOptions] = useState<Role[]>(appliedRoles);
const [selectedBuiltInRole, setSelectedBuiltInRole] = useState<OrgRole | undefined>(builtInRole); const [selectedBuiltInRole, setSelectedBuiltInRole] = useState<OrgRole | undefined>(basicRole);
const [showSubMenu, setShowSubMenu] = useState(false); const [showSubMenu, setShowSubMenu] = useState(false);
const [openedMenuGroup, setOpenedMenuGroup] = useState(''); const [openedMenuGroup, setOpenedMenuGroup] = useState('');
const [subMenuOptions, setSubMenuOptions] = useState<Role[]>([]); const [subMenuOptions, setSubMenuOptions] = useState<Role[]>([]);
@ -75,10 +75,10 @@ export const RolePickerMenu = ({
}, [selectedOptions, onSelect]); }, [selectedOptions, onSelect]);
useEffect(() => { useEffect(() => {
if (onBuiltInRoleSelect && selectedBuiltInRole) { if (onBasicRoleSelect && selectedBuiltInRole) {
onBuiltInRoleSelect(selectedBuiltInRole); onBasicRoleSelect(selectedBuiltInRole);
} }
}, [selectedBuiltInRole, onBuiltInRoleSelect]); }, [selectedBuiltInRole, onBasicRoleSelect]);
const customRoles = options.filter(filterCustomRoles).sort(sortRolesByName); const customRoles = options.filter(filterCustomRoles).sort(sortRolesByName);
const fixedRoles = options.filter(filterFixedRoles).sort(sortRolesByName); const fixedRoles = options.filter(filterFixedRoles).sort(sortRolesByName);
@ -188,16 +188,16 @@ export const RolePickerMenu = ({
> >
<div className={customStyles.menu} aria-label="Role picker menu"> <div className={customStyles.menu} aria-label="Role picker menu">
<CustomScrollbar autoHide={false} autoHeightMax={`${MENU_MAX_HEIGHT}px`} hideHorizontalTrack hideVerticalTrack> <CustomScrollbar autoHide={false} autoHeightMax={`${MENU_MAX_HEIGHT}px`} hideHorizontalTrack hideVerticalTrack>
{showBuiltInRole && ( {showBasicRole && (
<div className={customStyles.menuSection}> <div className={customStyles.menuSection}>
<div className={customStyles.groupHeader}>Basic roles</div> <div className={customStyles.groupHeader}>Basic roles</div>
<RadioButtonGroup <RadioButtonGroup
className={customStyles.builtInRoleSelector} className={customStyles.basicRoleSelector}
options={BuiltinRoleOption} options={BasicRoleOption}
value={selectedBuiltInRole} value={selectedBuiltInRole}
onChange={onSelectedBuiltinRoleChange} onChange={onSelectedBuiltinRoleChange}
fullWidth={true} fullWidth={true}
disabled={builtinRolesDisabled} disabled={basicRoleDisabled}
/> />
</div> </div>
)} )}
@ -621,7 +621,7 @@ export const getStyles = (theme: GrafanaTheme2) => {
menuOptionInfoSign: css` menuOptionInfoSign: css`
color: ${theme.colors.text.disabled}; color: ${theme.colors.text.disabled};
`, `,
builtInRoleSelector: css` basicRoleSelector: css`
margin: ${theme.spacing(1, 1.25, 1, 1)}; margin: ${theme.spacing(1, 1.25, 1, 1)};
`, `,
subMenuPortal: css` subMenuPortal: css`

@ -13,10 +13,9 @@ export interface Props {
orgId?: number; orgId?: number;
roleOptions: Role[]; roleOptions: Role[];
disabled?: boolean; disabled?: boolean;
builtinRolesDisabled?: boolean;
} }
export const TeamRolePicker: FC<Props> = ({ teamId, orgId, roleOptions, disabled, builtinRolesDisabled }) => { export const TeamRolePicker: FC<Props> = ({ teamId, orgId, roleOptions, disabled }) => {
const [{ loading, value: appliedRoles = [] }, getTeamRoles] = useAsyncFn(async () => { const [{ loading, value: appliedRoles = [] }, getTeamRoles] = useAsyncFn(async () => {
try { try {
return await fetchTeamRoles(teamId, orgId); return await fetchTeamRoles(teamId, orgId);
@ -47,7 +46,6 @@ export const TeamRolePicker: FC<Props> = ({ teamId, orgId, roleOptions, disabled
appliedRoles={appliedRoles} appliedRoles={appliedRoles}
isLoading={loading} isLoading={loading}
disabled={disabled} disabled={disabled}
builtinRolesDisabled={builtinRolesDisabled}
canUpdateRoles={canUpdateRoles} canUpdateRoles={canUpdateRoles}
/> />
); );

@ -8,28 +8,26 @@ import { RolePicker } from './RolePicker';
import { fetchUserRoles, updateUserRoles } from './api'; import { fetchUserRoles, updateUserRoles } from './api';
export interface Props { export interface Props {
builtInRole: OrgRole; basicRole: OrgRole;
userId: number; userId: number;
orgId?: number; orgId?: number;
onBuiltinRoleChange: (newRole: OrgRole) => void; onBasicRoleChange: (newRole: OrgRole) => void;
roleOptions: Role[]; roleOptions: Role[];
builtInRoles?: { [key: string]: Role[] };
disabled?: boolean; disabled?: boolean;
builtinRolesDisabled?: boolean; basicRoleDisabled?: boolean;
apply?: boolean; apply?: boolean;
onApplyRoles?: (newRoles: Role[], userId: number, orgId: number | undefined) => void; onApplyRoles?: (newRoles: Role[], userId: number, orgId: number | undefined) => void;
pendingRoles?: Role[]; pendingRoles?: Role[];
} }
export const UserRolePicker: FC<Props> = ({ export const UserRolePicker: FC<Props> = ({
builtInRole, basicRole,
userId, userId,
orgId, orgId,
onBuiltinRoleChange, onBasicRoleChange,
roleOptions, roleOptions,
builtInRoles,
disabled, disabled,
builtinRolesDisabled, basicRoleDisabled,
apply = false, apply = false,
onApplyRoles, onApplyRoles,
pendingRoles, pendingRoles,
@ -74,15 +72,14 @@ export const UserRolePicker: FC<Props> = ({
return ( return (
<RolePicker <RolePicker
appliedRoles={appliedRoles} appliedRoles={appliedRoles}
builtInRole={builtInRole} basicRole={basicRole}
onRolesChange={onRolesChange} onRolesChange={onRolesChange}
onBuiltinRoleChange={onBuiltinRoleChange} onBasicRoleChange={onBasicRoleChange}
roleOptions={roleOptions} roleOptions={roleOptions}
builtInRoles={builtInRoles}
isLoading={loading} isLoading={loading}
disabled={disabled} disabled={disabled}
builtinRolesDisabled={builtinRolesDisabled} basicRoleDisabled={basicRoleDisabled}
showBuiltInRole showBasicRole
apply={apply} apply={apply}
canUpdateRoles={canUpdateRoles} canUpdateRoles={canUpdateRoles}
/> />

@ -13,14 +13,6 @@ export const fetchRoleOptions = async (orgId?: number, query?: string): Promise<
return roles; return roles;
}; };
export const fetchBuiltinRoles = (orgId?: number): Promise<{ [key: string]: Role[] }> => {
let builtinRolesUrl = '/api/access-control/builtin-roles';
if (orgId) {
builtinRolesUrl += `?targetOrgId=${orgId}`;
}
return getBackendSrv().get(builtinRolesUrl);
};
export const fetchUserRoles = async (userId: number, orgId?: number): Promise<Role[]> => { export const fetchUserRoles = async (userId: number, orgId?: number): Promise<Role[]> => {
let userRolesUrl = `/api/access-control/users/${userId}/roles`; let userRolesUrl = `/api/access-control/users/${userId}/roles`;
if (orgId) { if (orgId) {

@ -112,10 +112,6 @@ export class ContextSrv {
return config.rbacEnabled; return config.rbacEnabled;
} }
accessControlBuiltInRoleAssignmentEnabled(): boolean {
return config.rbacBuiltInRoleAssignmentEnabled;
}
licensedAccessControlEnabled(): boolean { licensedAccessControlEnabled(): boolean {
return featureEnabled('accesscontrol') && config.rbacEnabled; return featureEnabled('accesscontrol') && config.rbacEnabled;
} }

@ -144,7 +144,6 @@ class UnThemedOrgRow extends PureComponent<OrgRowProps> {
currentRole: this.props.org.role, currentRole: this.props.org.role,
isChangingRole: false, isChangingRole: false,
roleOptions: [], roleOptions: [],
builtInRoles: {},
}; };
componentDidMount() { componentDidMount() {
@ -179,7 +178,7 @@ class UnThemedOrgRow extends PureComponent<OrgRowProps> {
this.setState({ isChangingRole: false }); this.setState({ isChangingRole: false });
}; };
onBuiltinRoleChange = (newRole: OrgRole) => { onBasicRoleChange = (newRole: OrgRole) => {
this.props.onOrgRoleChange(this.props.org.orgId, newRole); this.props.onOrgRoleChange(this.props.org.orgId, newRole);
}; };
@ -205,11 +204,10 @@ class UnThemedOrgRow extends PureComponent<OrgRowProps> {
<UserRolePicker <UserRolePicker
userId={user?.id || 0} userId={user?.id || 0}
orgId={org.orgId} orgId={org.orgId}
builtInRole={org.role} basicRole={org.role}
roleOptions={this.state.roleOptions} roleOptions={this.state.roleOptions}
builtInRoles={this.state.builtInRoles} onBasicRoleChange={this.onBasicRoleChange}
onBuiltinRoleChange={this.onBuiltinRoleChange} basicRoleDisabled={rolePickerDisabled}
builtinRolesDisabled={rolePickerDisabled}
/> />
</div> </div>
{isExternalUser && <ExternalUserTooltip />} {isExternalUser && <ExternalUserTooltip />}
@ -377,9 +375,9 @@ export class AddToOrgModal extends PureComponent<AddToOrgModalProps, AddToOrgMod
<UserRolePicker <UserRolePicker
userId={user?.id || 0} userId={user?.id || 0}
orgId={selectedOrg?.id} orgId={selectedOrg?.id}
builtInRole={role} basicRole={role}
onBuiltinRoleChange={this.onOrgRoleChange} onBasicRoleChange={this.onOrgRoleChange}
builtinRolesDisabled={false} basicRoleDisabled={false}
roleOptions={roleOptions} roleOptions={roleOptions}
apply={true} apply={true}
onApplyRoles={this.onRoleUpdate} onApplyRoles={this.onRoleUpdate}

@ -4,7 +4,7 @@ import { getBackendSrv, locationService } from '@grafana/runtime';
import { Form, Button, Input, Field, FieldSet } from '@grafana/ui'; import { Form, Button, Input, Field, FieldSet } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page'; import { Page } from 'app/core/components/Page/Page';
import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker'; import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker';
import { fetchBuiltinRoles, fetchRoleOptions, updateUserRoles } from 'app/core/components/RolePicker/api'; import { fetchRoleOptions, updateUserRoles } from 'app/core/components/RolePicker/api';
import { contextSrv } from 'app/core/core'; import { contextSrv } from 'app/core/core';
import { AccessControlAction, OrgRole, Role, ServiceAccountCreateApiResponse, ServiceAccountDTO } from 'app/types'; import { AccessControlAction, OrgRole, Role, ServiceAccountCreateApiResponse, ServiceAccountDTO } from 'app/types';
@ -23,7 +23,6 @@ const updateServiceAccount = async (id: number, sa: ServiceAccountDTO) =>
export const ServiceAccountCreatePage = ({}: Props): JSX.Element => { export const ServiceAccountCreatePage = ({}: Props): JSX.Element => {
const [roleOptions, setRoleOptions] = useState<Role[]>([]); const [roleOptions, setRoleOptions] = useState<Role[]>([]);
const [builtinRoles, setBuiltinRoles] = useState<{ [key: string]: Role[] }>({});
const [pendingRoles, setPendingRoles] = useState<Role[]>([]); const [pendingRoles, setPendingRoles] = useState<Role[]>([]);
const currentOrgId = contextSrv.user.orgId; const currentOrgId = contextSrv.user.orgId;
@ -46,14 +45,6 @@ export const ServiceAccountCreatePage = ({}: Props): JSX.Element => {
let options = await fetchRoleOptions(currentOrgId); let options = await fetchRoleOptions(currentOrgId);
setRoleOptions(options); setRoleOptions(options);
} }
if (
contextSrv.accessControlBuiltInRoleAssignmentEnabled() &&
contextSrv.hasPermission(AccessControlAction.ActionBuiltinRolesList)
) {
const builtInRoles = await fetchBuiltinRoles(currentOrgId);
setBuiltinRoles(builtInRoles);
}
} catch (e) { } catch (e) {
console.error('Error loading options', e); console.error('Error loading options', e);
} }
@ -131,9 +122,8 @@ export const ServiceAccountCreatePage = ({}: Props): JSX.Element => {
apply apply
userId={serviceAccount.id || 0} userId={serviceAccount.id || 0}
orgId={serviceAccount.orgId} orgId={serviceAccount.orgId}
builtInRole={serviceAccount.role} basicRole={serviceAccount.role}
builtInRoles={builtinRoles} onBasicRoleChange={onRoleChange}
onBuiltinRoleChange={onRoleChange}
roleOptions={roleOptions} roleOptions={roleOptions}
onApplyRoles={onPendingRolesUpdate} onApplyRoles={onPendingRolesUpdate}
pendingRoles={pendingRoles} pendingRoles={pendingRoles}

@ -26,7 +26,6 @@ const setup = (propOverrides: Partial<Props>) => {
const props: Props = { const props: Props = {
serviceAccount: {} as ServiceAccountDTO, serviceAccount: {} as ServiceAccountDTO,
tokens: [], tokens: [],
builtInRoles: {},
isLoading: false, isLoading: false,
roleOptions: [], roleOptions: [],
match: { match: {

@ -28,7 +28,6 @@ interface OwnProps extends GrafanaRouteComponentProps<{ id: string }> {
tokens: ApiKey[]; tokens: ApiKey[];
isLoading: boolean; isLoading: boolean;
roleOptions: Role[]; roleOptions: Role[];
builtInRoles: Record<string, Role[]>;
} }
function mapStateToProps(state: StoreState) { function mapStateToProps(state: StoreState) {
@ -37,7 +36,6 @@ function mapStateToProps(state: StoreState) {
tokens: state.serviceAccountProfile.tokens, tokens: state.serviceAccountProfile.tokens,
isLoading: state.serviceAccountProfile.isLoading, isLoading: state.serviceAccountProfile.isLoading,
roleOptions: state.serviceAccounts.roleOptions, roleOptions: state.serviceAccounts.roleOptions,
builtInRoles: state.serviceAccounts.builtInRoles,
timezone: getTimeZone(state.user), timezone: getTimeZone(state.user),
}; };
} }
@ -62,7 +60,6 @@ export const ServiceAccountPageUnconnected = ({
timezone, timezone,
isLoading, isLoading,
roleOptions, roleOptions,
builtInRoles,
createServiceAccountToken, createServiceAccountToken,
deleteServiceAccount, deleteServiceAccount,
deleteServiceAccountToken, deleteServiceAccountToken,
@ -187,7 +184,6 @@ export const ServiceAccountPageUnconnected = ({
serviceAccount={serviceAccount} serviceAccount={serviceAccount}
timeZone={timezone} timeZone={timezone}
roleOptions={roleOptions} roleOptions={roleOptions}
builtInRoles={builtInRoles}
onChange={onProfileChange} onChange={onProfileChange}
/> />
)} )}

@ -26,7 +26,6 @@ const setup = (propOverrides: Partial<Props>) => {
const getApiKeysMigrationInfoMock = jest.fn(); const getApiKeysMigrationInfoMock = jest.fn();
const closeApiKeysMigrationInfoMock = jest.fn(); const closeApiKeysMigrationInfoMock = jest.fn();
const props: Props = { const props: Props = {
builtInRoles: {},
isLoading: false, isLoading: false,
page: 0, page: 0,
perPage: 10, perPage: 10,

@ -55,7 +55,6 @@ export const ServiceAccountsListPageUnconnected = ({
serviceAccounts, serviceAccounts,
isLoading, isLoading,
roleOptions, roleOptions,
builtInRoles,
query, query,
serviceAccountStateFilter, serviceAccountStateFilter,
apiKeysMigrated, apiKeysMigrated,
@ -268,7 +267,6 @@ export const ServiceAccountsListPageUnconnected = ({
<ServiceAccountListItem <ServiceAccountListItem
serviceAccount={serviceAccount} serviceAccount={serviceAccount}
key={serviceAccount.id} key={serviceAccount.id}
builtInRoles={builtInRoles}
roleOptions={roleOptions} roleOptions={roleOptions}
onRoleChange={onRoleChange} onRoleChange={onRoleChange}
onRemoveButtonClick={onRemoveButtonClick} onRemoveButtonClick={onRemoveButtonClick}

@ -13,17 +13,10 @@ interface Props {
serviceAccount: ServiceAccountDTO; serviceAccount: ServiceAccountDTO;
timeZone: TimeZone; timeZone: TimeZone;
roleOptions: Role[]; roleOptions: Role[];
builtInRoles: Record<string, Role[]>;
onChange: (serviceAccount: ServiceAccountDTO) => void; onChange: (serviceAccount: ServiceAccountDTO) => void;
} }
export function ServiceAccountProfile({ export function ServiceAccountProfile({ serviceAccount, timeZone, roleOptions, onChange }: Props): JSX.Element {
serviceAccount,
timeZone,
roleOptions,
builtInRoles,
onChange,
}: Props): JSX.Element {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const ableToWrite = contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite); const ableToWrite = contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite);
@ -51,7 +44,6 @@ export function ServiceAccountProfile({
label="Roles" label="Roles"
serviceAccount={serviceAccount} serviceAccount={serviceAccount}
onRoleChange={onRoleChange} onRoleChange={onRoleChange}
builtInRoles={builtInRoles}
roleOptions={roleOptions} roleOptions={roleOptions}
/> />
<ServiceAccountProfileRow <ServiceAccountProfileRow

@ -11,16 +11,9 @@ interface Props {
serviceAccount: ServiceAccountDTO; serviceAccount: ServiceAccountDTO;
onRoleChange: (role: OrgRole) => void; onRoleChange: (role: OrgRole) => void;
roleOptions: Role[]; roleOptions: Role[];
builtInRoles: Record<string, Role[]>;
} }
export const ServiceAccountRoleRow = ({ export const ServiceAccountRoleRow = ({ label, serviceAccount, roleOptions, onRoleChange }: Props): JSX.Element => {
label,
serviceAccount,
roleOptions,
builtInRoles,
onRoleChange,
}: Props): JSX.Element => {
const inputId = `${label}-input`; const inputId = `${label}-input`;
const canUpdateRole = contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsWrite, serviceAccount); const canUpdateRole = contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsWrite, serviceAccount);
@ -34,11 +27,10 @@ export const ServiceAccountRoleRow = ({
<UserRolePicker <UserRolePicker
userId={serviceAccount.id} userId={serviceAccount.id}
orgId={serviceAccount.orgId} orgId={serviceAccount.orgId}
builtInRole={serviceAccount.role} basicRole={serviceAccount.role}
onBuiltinRoleChange={onRoleChange} onBasicRoleChange={onRoleChange}
roleOptions={roleOptions} roleOptions={roleOptions}
builtInRoles={builtInRoles} basicRoleDisabled={!canUpdateRole}
builtinRolesDisabled={!canUpdateRole}
disabled={serviceAccount.isDisabled} disabled={serviceAccount.isDisabled}
/> />
</td> </td>

@ -12,7 +12,6 @@ type ServiceAccountListItemProps = {
serviceAccount: ServiceAccountDTO; serviceAccount: ServiceAccountDTO;
onRoleChange: (role: OrgRole, serviceAccount: ServiceAccountDTO) => void; onRoleChange: (role: OrgRole, serviceAccount: ServiceAccountDTO) => void;
roleOptions: Role[]; roleOptions: Role[];
builtInRoles: Record<string, Role[]>;
onRemoveButtonClick: (serviceAccount: ServiceAccountDTO) => void; onRemoveButtonClick: (serviceAccount: ServiceAccountDTO) => void;
onDisable: (serviceAccount: ServiceAccountDTO) => void; onDisable: (serviceAccount: ServiceAccountDTO) => void;
onEnable: (serviceAccount: ServiceAccountDTO) => void; onEnable: (serviceAccount: ServiceAccountDTO) => void;
@ -28,7 +27,6 @@ const ServiceAccountListItem = memo(
serviceAccount, serviceAccount,
onRoleChange, onRoleChange,
roleOptions, roleOptions,
builtInRoles,
onRemoveButtonClick, onRemoveButtonClick,
onDisable, onDisable,
onEnable, onEnable,
@ -78,11 +76,10 @@ const ServiceAccountListItem = memo(
<UserRolePicker <UserRolePicker
userId={serviceAccount.id} userId={serviceAccount.id}
orgId={serviceAccount.orgId} orgId={serviceAccount.orgId}
builtInRole={serviceAccount.role} basicRole={serviceAccount.role}
onBuiltinRoleChange={(newRole) => onRoleChange(newRole, serviceAccount)} onBasicRoleChange={(newRole) => onRoleChange(newRole, serviceAccount)}
roleOptions={roleOptions} roleOptions={roleOptions}
builtInRoles={builtInRoles} basicRoleDisabled={!canUpdateRole}
builtinRolesDisabled={!canUpdateRole}
disabled={serviceAccount.isDisabled} disabled={serviceAccount.isDisabled}
/> />
)} )}

@ -1,7 +1,7 @@
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
import { fetchBuiltinRoles, fetchRoleOptions } from 'app/core/components/RolePicker/api'; import { fetchRoleOptions } from 'app/core/components/RolePicker/api';
import { contextSrv } from 'app/core/services/context_srv'; import { contextSrv } from 'app/core/services/context_srv';
import store from 'app/core/store'; import store from 'app/core/store';
import { AccessControlAction, ServiceAccountDTO, ServiceAccountStateFilter, ThunkResult } from 'app/types'; import { AccessControlAction, ServiceAccountDTO, ServiceAccountStateFilter, ThunkResult } from 'app/types';
@ -11,7 +11,6 @@ import { API_KEYS_MIGRATION_INFO_STORAGE_KEY } from '../constants';
import { import {
acOptionsLoaded, acOptionsLoaded,
builtInRolesLoaded,
pageChanged, pageChanged,
queryChanged, queryChanged,
serviceAccountsFetchBegin, serviceAccountsFetchBegin,
@ -31,14 +30,6 @@ export function fetchACOptions(): ThunkResult<void> {
const options = await fetchRoleOptions(); const options = await fetchRoleOptions();
dispatch(acOptionsLoaded(options)); dispatch(acOptionsLoaded(options));
} }
if (
contextSrv.accessControlBuiltInRoleAssignmentEnabled() &&
contextSrv.licensedAccessControlEnabled() &&
contextSrv.hasPermission(AccessControlAction.ActionBuiltinRolesList)
) {
const builtInRoles = await fetchBuiltinRoles();
dispatch(builtInRolesLoaded(builtInRoles));
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }

@ -43,7 +43,6 @@ export const { serviceAccountLoaded, serviceAccountTokensLoaded, serviceAccountF
export const initialStateList: ServiceAccountsState = { export const initialStateList: ServiceAccountsState = {
serviceAccounts: [] as ServiceAccountDTO[], serviceAccounts: [] as ServiceAccountDTO[],
isLoading: true, isLoading: true,
builtInRoles: {},
roleOptions: [], roleOptions: [],
query: '', query: '',
page: 0, page: 0,
@ -88,9 +87,6 @@ const serviceAccountsSlice = createSlice({
acOptionsLoaded: (state, action: PayloadAction<Role[]>): ServiceAccountsState => { acOptionsLoaded: (state, action: PayloadAction<Role[]>): ServiceAccountsState => {
return { ...state, roleOptions: action.payload }; return { ...state, roleOptions: action.payload };
}, },
builtInRolesLoaded: (state, action: PayloadAction<Record<string, Role[]>>): ServiceAccountsState => {
return { ...state, builtInRoles: action.payload };
},
apiKeysMigrationStatusLoaded: (state, action): ServiceAccountsState => { apiKeysMigrationStatusLoaded: (state, action): ServiceAccountsState => {
return { ...state, apiKeysMigrated: action.payload }; return { ...state, apiKeysMigrated: action.payload };
}, },
@ -121,7 +117,6 @@ export const {
serviceAccountsFetchEnd, serviceAccountsFetchEnd,
serviceAccountsFetched, serviceAccountsFetched,
acOptionsLoaded, acOptionsLoaded,
builtInRolesLoaded,
apiKeysMigrationStatusLoaded, apiKeysMigrationStatusLoaded,
showApiKeysMigrationInfoLoaded, showApiKeysMigrationInfoLoaded,
pageChanged, pageChanged,

@ -3,7 +3,7 @@ import React, { FC, useEffect, useState } from 'react';
import { OrgRole } from '@grafana/data'; import { OrgRole } from '@grafana/data';
import { Button, ConfirmModal } from '@grafana/ui'; import { Button, ConfirmModal } from '@grafana/ui';
import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker'; import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker';
import { fetchBuiltinRoles, fetchRoleOptions } from 'app/core/components/RolePicker/api'; import { fetchRoleOptions } from 'app/core/components/RolePicker/api';
import { contextSrv } from 'app/core/core'; import { contextSrv } from 'app/core/core';
import { AccessControlAction, OrgUser, Role } from 'app/types'; import { AccessControlAction, OrgUser, Role } from 'app/types';
@ -20,7 +20,6 @@ const UsersTable: FC<Props> = (props) => {
const { users, orgId, onRoleChange, onRemoveUser } = props; const { users, orgId, onRoleChange, onRemoveUser } = props;
const [userToRemove, setUserToRemove] = useState<OrgUser | null>(null); const [userToRemove, setUserToRemove] = useState<OrgUser | null>(null);
const [roleOptions, setRoleOptions] = useState<Role[]>([]); const [roleOptions, setRoleOptions] = useState<Role[]>([]);
const [builtinRoles, setBuiltinRoles] = useState<{ [key: string]: Role[] }>({});
useEffect(() => { useEffect(() => {
async function fetchOptions() { async function fetchOptions() {
@ -29,14 +28,6 @@ const UsersTable: FC<Props> = (props) => {
let options = await fetchRoleOptions(orgId); let options = await fetchRoleOptions(orgId);
setRoleOptions(options); setRoleOptions(options);
} }
if (
contextSrv.accessControlBuiltInRoleAssignmentEnabled() &&
contextSrv.hasPermission(AccessControlAction.ActionBuiltinRolesList)
) {
const builtInRoles = await fetchBuiltinRoles(orgId);
setBuiltinRoles(builtInRoles);
}
} catch (e) { } catch (e) {
console.error('Error loading options'); console.error('Error loading options');
} }
@ -92,12 +83,9 @@ const UsersTable: FC<Props> = (props) => {
userId={user.userId} userId={user.userId}
orgId={orgId} orgId={orgId}
roleOptions={roleOptions} roleOptions={roleOptions}
builtInRoles={builtinRoles} basicRole={user.role}
builtInRole={user.role} onBasicRoleChange={(newRole) => onRoleChange(newRole, user)}
onBuiltinRoleChange={(newRole) => onRoleChange(newRole, user)} basicRoleDisabled={!contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersWrite, user)}
builtinRolesDisabled={
!contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersWrite, user)
}
/> />
) : ( ) : (
<OrgRolePicker <OrgRolePicker

@ -63,7 +63,6 @@ export enum AccessControlAction {
ActionTeamsPermissionsWrite = 'teams.permissions:write', ActionTeamsPermissionsWrite = 'teams.permissions:write',
ActionRolesList = 'roles:read', ActionRolesList = 'roles:read',
ActionBuiltinRolesList = 'roles.builtin:list',
ActionTeamsRolesList = 'teams.roles:read', ActionTeamsRolesList = 'teams.roles:read',
ActionTeamsRolesAdd = 'teams.roles:add', ActionTeamsRolesAdd = 'teams.roles:add',
ActionTeamsRolesRemove = 'teams.roles:remove', ActionTeamsRolesRemove = 'teams.roles:remove',

@ -65,7 +65,6 @@ export interface ServiceAccountsState {
serviceAccounts: ServiceAccountDTO[]; serviceAccounts: ServiceAccountDTO[];
isLoading: boolean; isLoading: boolean;
roleOptions: Role[]; roleOptions: Role[];
builtInRoles: Record<string, Role[]>;
apiKeysMigrated: boolean; apiKeysMigrated: boolean;
showApiKeysMigrationInfo: boolean; showApiKeysMigrationInfo: boolean;

Loading…
Cancel
Save