Access control: Allow users with permission to update team, dashboard and folder permissions to list users in OSS (#48275)

* Remove banner when missing permissions to list users

* For OSS allow users to list other users if they have permissions to
write either team, dashboard or folder permissions
pull/48802/head
Karl Persson 3 years ago committed by GitHub
parent 9826a694a8
commit 817cf52744
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      pkg/api/api.go
  2. 2
      pkg/services/sqlstore/org_users.go
  3. 4
      pkg/services/sqlstore/org_users_test.go
  4. 34
      public/app/core/components/AccessControl/AddPermission.tsx
  5. 4
      public/app/core/components/AccessControl/Permissions.tsx
  6. 1
      public/app/core/components/AccessControl/types.ts
  7. 10
      public/app/features/dashboard/components/DashboardPermissions/AccessControlDashboardPermissions.tsx
  8. 8
      public/app/features/folders/AccessControlFolderPermissions.tsx
  9. 2
      public/app/features/teams/TeamPermissions.tsx

@ -249,7 +249,19 @@ func (hs *HTTPServer) registerRoutes() {
// current org without requirement of user to be org admin
apiRoute.Group("/org", func(orgRoute routing.RouteRegister) {
orgRoute.Get("/users/lookup", authorize(reqOrgAdminFolderAdminOrTeamAdmin, ac.EvalPermission(ac.ActionOrgUsersRead)), routing.Wrap(hs.GetOrgUsersForCurrentOrgLookup))
lookupEvaluator := func() ac.Evaluator {
if hs.Cfg.IsEnterprise {
return ac.EvalPermission(ac.ActionOrgUsersRead)
}
// For oss we allow users with access to update permissions on either folders, teams or dashboards to perform the lookup
return ac.EvalAny(
ac.EvalPermission(ac.ActionOrgUsersRead),
ac.EvalPermission(ac.ActionTeamsPermissionsWrite),
ac.EvalPermission(dashboards.ActionDashboardsPermissionsWrite),
ac.EvalPermission(dashboards.ActionFoldersPermissionsWrite),
)
}
orgRoute.Get("/users/lookup", authorize(reqOrgAdminFolderAdminOrTeamAdmin, lookupEvaluator()), routing.Wrap(hs.GetOrgUsersForCurrentOrgLookup))
})
// create new org

@ -109,7 +109,7 @@ func (ss *SQLStore) GetOrgUsers(ctx context.Context, query *models.GetOrgUsersQu
whereConditions = append(whereConditions, fmt.Sprintf("%s.is_service_account = ?", ss.Dialect.Quote("user")))
whereParams = append(whereParams, ss.Dialect.BooleanStr(false))
if !accesscontrol.IsDisabled(ss.Cfg) && query.User != nil {
if ss.Cfg.IsEnterprise && !accesscontrol.IsDisabled(ss.Cfg) && query.User != nil {
acFilter, err := accesscontrol.Filter(query.User, "org_user.user_id", "users:id:", accesscontrol.ActionOrgUsersRead)
if err != nil {
return err

@ -62,6 +62,10 @@ func TestSQLStore_GetOrgUsers(t *testing.T) {
}
store := InitTestDB(t, InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagAccesscontrol}})
store.Cfg.IsEnterprise = true
defer func() {
store.Cfg.IsEnterprise = false
}()
seedOrgUsers(t, store, 10)
for _, tt := range tests {

@ -1,6 +1,6 @@
import React, { useEffect, useMemo, useState } from 'react';
import { Alert, Button, Form, HorizontalGroup, Input, Select } from '@grafana/ui';
import { Button, Form, HorizontalGroup, Select } from '@grafana/ui';
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
import { TeamPicker } from 'app/core/components/Select/TeamPicker';
import { UserPicker } from 'app/core/components/Select/UserPicker';
@ -12,20 +12,12 @@ export interface Props {
title?: string;
permissions: string[];
assignments: Assignments;
canListUsers: boolean;
onCancel: () => void;
onAdd: (state: SetPermission) => void;
}
export const AddPermission = ({
title = 'Add Permission For',
permissions,
assignments,
canListUsers,
onAdd,
onCancel,
}: Props) => {
const [target, setPermissionTarget] = useState<PermissionTarget>(PermissionTarget.User);
export const AddPermission = ({ title = 'Add Permission For', permissions, assignments, onAdd, onCancel }: Props) => {
const [target, setPermissionTarget] = useState<PermissionTarget>(PermissionTarget.None);
const [teamId, setTeamId] = useState(0);
const [userId, setUserId] = useState(0);
const [builtInRole, setBuiltinRole] = useState('');
@ -33,8 +25,8 @@ export const AddPermission = ({
const targetOptions = useMemo(() => {
const options = [];
if (assignments.users && canListUsers) {
options.push({ value: PermissionTarget.User, label: 'User', isDisabled: false });
if (assignments.users) {
options.push({ value: PermissionTarget.User, label: 'User' });
}
if (assignments.teams) {
options.push({ value: PermissionTarget.Team, label: 'Team' });
@ -43,7 +35,7 @@ export const AddPermission = ({
options.push({ value: PermissionTarget.BuiltInRole, label: 'Role' });
}
return options;
}, [assignments, canListUsers]);
}, [assignments]);
useEffect(() => {
if (permissions.length > 0) {
@ -56,22 +48,11 @@ export const AddPermission = ({
(target === PermissionTarget.User && userId > 0) ||
(PermissionTarget.BuiltInRole && OrgRole.hasOwnProperty(builtInRole));
const renderMissingListUserRights = () => {
return (
<Alert severity="info" title="Missing permission">
You are missing the permission to list users (org.users:read). Please contact your administrator to get this
resolved.
</Alert>
);
};
return (
<div className="cta-form" aria-label="Permissions slider">
<CloseButton onClick={onCancel} />
<h5>{title}</h5>
{target === PermissionTarget.User && !canListUsers && renderMissingListUserRights()}
<Form
name="addPermission"
maxWidth="none"
@ -87,10 +68,9 @@ export const AddPermission = ({
disabled={targetOptions.length === 0}
/>
{target === PermissionTarget.User && canListUsers && (
{target === PermissionTarget.User && (
<UserPicker onSelected={(u) => setUserId(u.value || 0)} className={'width-20'} />
)}
{target === PermissionTarget.User && !canListUsers && <Input disabled={true} className={'width-20'} />}
{target === PermissionTarget.Team && (
<TeamPicker onSelected={(t) => setTeamId(t.value?.id || 0)} className={'width-20'} />

@ -29,8 +29,6 @@ export type Props = {
addPermissionTitle?: string;
resource: string;
resourceId: ResourceId;
canListUsers: boolean;
canSetPermissions: boolean;
};
@ -39,7 +37,6 @@ export const Permissions = ({
buttonLabel = 'Add a permission',
resource,
resourceId,
canListUsers,
canSetPermissions,
addPermissionTitle,
}: Props) => {
@ -145,7 +142,6 @@ export const Permissions = ({
onAdd={onAdd}
permissions={desc.permissions}
assignments={desc.assignments}
canListUsers={canListUsers}
onCancel={() => setIsAdding(false)}
/>
</SlideDown>

@ -22,6 +22,7 @@ export type SetPermission = {
};
export enum PermissionTarget {
None = 'None',
Team = 'Team',
User = 'User',
BuiltInRole = 'builtInRole',

@ -11,15 +11,7 @@ interface Props {
}
export const AccessControlDashboardPermissions = ({ dashboard }: Props) => {
const canListUsers = contextSrv.hasPermission(AccessControlAction.OrgUsersRead);
const canSetPermissions = contextSrv.hasPermission(AccessControlAction.DashboardsPermissionsWrite);
return (
<Permissions
resource={'dashboards'}
resourceId={dashboard.uid}
canListUsers={canListUsers}
canSetPermissions={canSetPermissions}
/>
);
return <Permissions resource={'dashboards'} resourceId={dashboard.uid} canSetPermissions={canSetPermissions} />;
};

@ -33,18 +33,12 @@ export const AccessControlFolderPermissions = ({ uid, getFolderByUid, navModel }
getFolderByUid(uid);
}, [getFolderByUid, uid]);
const canListUsers = contextSrv.hasPermission(AccessControlAction.OrgUsersRead);
const canSetPermissions = contextSrv.hasPermission(AccessControlAction.FoldersPermissionsWrite);
return (
<Page navModel={navModel}>
<Page.Contents>
<Permissions
resource="folders"
resourceId={uid}
canListUsers={canListUsers}
canSetPermissions={canSetPermissions}
/>
<Permissions resource="folders" resourceId={uid} canSetPermissions={canSetPermissions} />
</Page.Contents>
</Page>
);

@ -11,7 +11,6 @@ type TeamPermissionsProps = {
// TeamPermissions component replaces TeamMembers component when the accesscontrol feature flag is set
const TeamPermissions = (props: TeamPermissionsProps) => {
const canListUsers = contextSrv.hasPermission(AccessControlAction.OrgUsersRead);
const canSetPermissions = contextSrv.hasPermissionInMetadata(
AccessControlAction.ActionTeamsPermissionsWrite,
props.team
@ -24,7 +23,6 @@ const TeamPermissions = (props: TeamPermissionsProps) => {
buttonLabel="Add member"
resource="teams"
resourceId={props.team.id}
canListUsers={canListUsers}
canSetPermissions={canSetPermissions}
/>
);

Loading…
Cancel
Save