Access Control: hiding add annotation button without permissions (#47223)

* Access Control: hiding add annotation button without permissions
This commit is contained in:
Ezequiel Victorero 2022-04-05 08:20:10 -03:00 committed by GitHub
parent bf9e0e8bc8
commit 6a059dcb4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 78 additions and 38 deletions

View File

@ -202,7 +202,13 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
func (hs *HTTPServer) getAnnotationPermissionsByScope(c *models.ReqContext, actions *dtos.AnnotationActions, scope string) {
var err error
evaluate := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsDelete, scope)
evaluate := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsCreate, scope)
actions.CanAdd, err = hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluate)
if err != nil {
hs.log.Warn("Failed to evaluate permission", "err", err, "action", accesscontrol.ActionAnnotationsCreate, "scope", scope)
}
evaluate = accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsDelete, scope)
actions.CanDelete, err = hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluate)
if err != nil {
hs.log.Warn("Failed to evaluate permission", "err", err, "action", accesscontrol.ActionAnnotationsDelete, "scope", scope)

View File

@ -40,6 +40,7 @@ type AnnotationPermission struct {
}
type AnnotationActions struct {
CanAdd bool `json:"canAdd"`
CanEdit bool `json:"canEdit"`
CanDelete bool `json:"canDelete"`
}

View File

@ -88,7 +88,7 @@ export class PanelChrome extends PureComponent<Props, State> {
onAnnotationCreate: this.onAnnotationCreate,
onAnnotationUpdate: this.onAnnotationUpdate,
onAnnotationDelete: this.onAnnotationDelete,
canAddAnnotations: () => Boolean(props.dashboard.meta.canEdit || props.dashboard.meta.canMakeEditable),
canAddAnnotations: this.canAddAnnotation,
onInstanceStateChange: this.onInstanceStateChange,
onToggleLegendSort: this.onToggleLegendSort,
canEditAnnotations: this.canEditAnnotation,
@ -98,6 +98,17 @@ export class PanelChrome extends PureComponent<Props, State> {
};
}
canEditDashboard = () => Boolean(this.props.dashboard.meta.canEdit || this.props.dashboard.meta.canMakeEditable);
canAddAnnotation = () => {
let canAdd = true;
if (contextSrv.accessControlEnabled()) {
canAdd = !!this.props.dashboard.meta.annotationsPermissions?.dashboard.canAdd;
}
return canAdd && this.canEditDashboard();
};
canEditAnnotation = (dashboardId: number) => {
let canEdit = true;
@ -108,7 +119,7 @@ export class PanelChrome extends PureComponent<Props, State> {
canEdit = !!this.props.dashboard.meta.annotationsPermissions?.organization.canEdit;
}
}
return canEdit && Boolean(this.props.dashboard.meta.canEdit || this.props.dashboard.meta.canMakeEditable);
return canEdit && this.canEditDashboard();
};
canDeleteAnnotation = (dashboardId: number) => {
@ -121,7 +132,7 @@ export class PanelChrome extends PureComponent<Props, State> {
canDelete = !!this.props.dashboard.meta.annotationsPermissions?.organization.canDelete;
}
}
return canDelete && Boolean(this.props.dashboard.meta.canEdit || this.props.dashboard.meta.canMakeEditable);
return canDelete && this.canEditDashboard();
};
// Due to a mutable panel model we get the sync settings via function that proactively reads from the model

View File

@ -863,7 +863,7 @@ describe('DashboardModel', () => {
dashboard.meta.canEdit = canEdit;
dashboard.meta.canMakeEditable = canMakeEditable;
const result = dashboard.canAddAnnotations();
const result = dashboard.canEditDashboard();
expect(result).toBe(expected);
}

View File

@ -1189,10 +1189,21 @@ export class DashboardModel implements TimeModel {
canEdit = !!this.meta.annotationsPermissions?.dashboard.canEdit;
}
}
return this.canAddAnnotations() && canEdit;
return this.canEditDashboard() && canEdit;
}
canAddAnnotations() {
let canAdd = true;
// if FGAC is enabled there are additional conditions to check
if (contextSrv.accessControlEnabled()) {
canAdd = !!this.meta.annotationsPermissions?.dashboard.canAdd;
}
return this.canEditDashboard() && canAdd;
}
canEditDashboard() {
return this.meta.canEdit || this.meta.canMakeEditable;
}

View File

@ -244,39 +244,49 @@ export const CandlestickPanel: React.FC<CandlestickPanelProps> = ({
<AnnotationsPlugin annotations={data.annotations} config={config} timeZone={timeZone} />
)}
{/* Enables annotations creation*/}
<AnnotationEditorPlugin data={alignedDataFrame} timeZone={timeZone} config={config}>
{({ startAnnotating }) => {
return (
<ContextMenuPlugin
data={alignedDataFrame}
config={config}
timeZone={timeZone}
replaceVariables={replaceVariables}
defaultItems={
enableAnnotationCreation
? [
{
items: [
{
label: 'Add annotation',
ariaLabel: 'Add annotation',
icon: 'comment-alt',
onClick: (e, p) => {
if (!p) {
return;
}
startAnnotating({ coords: p.coords });
{enableAnnotationCreation ? (
<AnnotationEditorPlugin data={alignedDataFrame} timeZone={timeZone} config={config}>
{({ startAnnotating }) => {
return (
<ContextMenuPlugin
data={alignedDataFrame}
config={config}
timeZone={timeZone}
replaceVariables={replaceVariables}
defaultItems={
enableAnnotationCreation
? [
{
items: [
{
label: 'Add annotation',
ariaLabel: 'Add annotation',
icon: 'comment-alt',
onClick: (e, p) => {
if (!p) {
return;
}
startAnnotating({ coords: p.coords });
},
},
},
],
},
]
: []
}
/>
);
}}
</AnnotationEditorPlugin>
],
},
]
: []
}
/>
);
}}
</AnnotationEditorPlugin>
) : (
<ContextMenuPlugin
data={alignedDataFrame}
config={config}
timeZone={timeZone}
replaceVariables={replaceVariables}
defaultItems={[]}
/>
)}
{data.annotations && (
<ExemplarsPlugin
config={config}

View File

@ -39,6 +39,7 @@ export interface DashboardMeta {
}
export interface AnnotationActions {
canAdd: boolean;
canEdit: boolean;
canDelete: boolean;
}