Skip to content

Commit

Permalink
[Cases] RBAC Bugs (#101325)
Browse files Browse the repository at this point in the history
* Adding feature flag for auth

* Hiding SOs and adding consumer field

* First pass at adding security changes

* Consumer as the app's plugin ID

* Create addConsumerToSO migration helper

* Fix mapping's SO consumer

* Add test for CasesActions

* Declare hidden types on SO client

* Restructure integration tests

* Init spaces_only integration tests

* Implementing the cases security string

* Adding security plugin tests for cases

* Rough concept for authorization class

* Adding comments

* Fix merge

* Get requiredPrivileges for classes

* Check privillages

* Ensure that all classes are available

* Success if hasAllRequested is true

* Failure if hasAllRequested is false

* Adding schema updates for feature plugin

* Seperate basic from trial

* Enable SIR on integration tests

* Starting the plumbing for authorization in plugin

* Unit tests working

* Move find route logic to case client

* Create integration test helper functions

* Adding auth to create call

* Create getClassFilter helper

* Add class attribute to find request

* Create getFindAuthorizationFilter

* Ensure savedObject is authorized in find method

* Include fields for authorization

* Combine authorization filter with cases & subcases filter

* Fix isAuthorized flag

* Fix merge issue

* Create/delete spaces & users before and after tests

* Add more user and roles

* [Cases] Convert filters from strings to KueryNode (#95288)

* [Cases] RBAC: Rename class to scope (#95535)

* [Cases][RBAC] Rename scope to owner (#96035)

* [Cases] RBAC: Create & Find integration tests (#95511)

* [Cases] Cases client enchantment (#95923)

* [Cases] Authorization and Client Audit Logger (#95477)

* Starting audit logger

* Finishing auth audit logger

* Fixing tests and types

* Adding audit event creator

* Renaming class to scope

* Adding audit logger messages to create and find

* Adding comments and fixing import issue

* Fixing type errors

* Fixing tests and adding username to message

* Addressing PR feedback

* Removing unneccessary log and generating id

* Fixing module issue and remove expect.anything

* [Cases] Migrate sub cases routes to a client (#96461)

* Adding sub cases client

* Move sub case routes to case client

* Throw when attempting to access the sub cases client

* Fixing throw and removing user ans soclients

* [Cases] RBAC: Migrate routes' unit tests to integration tests (#96374)

Co-authored-by: Jonathan Buttner <jonathan.buttner@elastic.co>

* [Cases] Move remaining HTTP functionality to client (#96507)

* Moving deletes and find for attachments

* Moving rest of comment apis

* Migrating configuration routes to client

* Finished moving routes, starting utils refactor

* Refactoring utilites and fixing integration tests

* Addressing PR feedback

* Fixing mocks and types

* Fixing integration tests

* Renaming status_stats

* Fixing test type errors

* Adding plugins to kibana.json

* Adding cases to required plugin

* [Cases] Refactoring authorization (#97483)

* Refactoring authorization

* Wrapping auth calls in helper for try catch

* Reverting name change

* Hardcoding the saved object types

* Switching ensure to owner array

* [Cases] Add authorization to configuration & cases routes (#97228)

* [Cases] Attachments RBAC (#97756)

* Starting rbac for comments

* Adding authorization to rest of comment apis

* Starting the comment rbac tests

* Fixing some of the rbac tests

* Adding some integration tests

* Starting patch tests

* Working tests for comments

* Working tests

* Fixing some tests

* Fixing type issues from pulling in master

* Fixing connector tests that only work in trial license

* Attempting to fix cypress

* Mock return of array for configure

* Fixing cypress test

* Cleaning up

* Addressing PR comments

* Reducing operations

* [Cases] Add RBAC to remaining Cases APIs (#98762)

* Starting rbac for comments

* Adding authorization to rest of comment apis

* Starting the comment rbac tests

* Fixing some of the rbac tests

* Adding some integration tests

* Starting patch tests

* Working tests for comments

* Working tests

* Fixing some tests

* Fixing type issues from pulling in master

* Fixing connector tests that only work in trial license

* Attempting to fix cypress

* Mock return of array for configure

* Fixing cypress test

* Cleaning up

* Working case update tests

* Addressing PR comments

* Reducing operations

* Working rbac push case tests

* Starting stats apis

* Working status tests

* User action tests and fixing migration errors

* Fixing type errors

* including error in message

* Addressing pr feedback

* Fixing some type errors

* [Cases] Add space only tests (#99409)

* Starting spaces tests

* Finishing space only tests

* Refactoring createCaseWithConnector

* Fixing spelling

* Addressing PR feedback and creating alert tests

* Fixing mocks

* [Cases] Add security only tests (#99679)

* Starting spaces tests

* Finishing space only tests

* Refactoring createCaseWithConnector

* Fixing spelling

* Addressing PR feedback and creating alert tests

* Fixing mocks

* Starting security only tests

* Adding remainder security only tests

* Using helper objects

* Fixing type error for null space

* Renaming utility variables

* Refactoring users and roles for security only tests

* Adding sub feature

* [Cases] Cleaning up the services and TODOs (#99723)

* Cleaning up the service intialization

* Fixing type errors

* Adding comments for the api

* Working test for cases client

* Fix type error

* Adding generated docs

* Adding more docs and cleaning up types

* Cleaning up readme

* More clean up and links

* Changing some file names

* Renaming docs

* Integration tests for cases privs and fixes (#100038)

* [Cases] RBAC on UI (#99478)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

* Fixing case ids by alert id route call

* [Cases] Fixing UI feature permissions and adding UI tests (#100074)

* Integration tests for cases privs and fixes

* Fixing ui cases permissions and adding tests

* Adding test for collection failure and fixing jest

* Renaming variables

* Fixing type error

* Adding some comments

* Validate cases features

* Fix new schema

* Adding owner param for the status stats

* Fix get case status tests

* Adjusting permissions text and fixing status

* Address PR feedback

* Adding top level feature back

* Fixing feature privileges

* Renaming

* Removing uneeded else

* Fixing tests and adding cases merge tests

* [Cases][Security Solution] Basic license security solution API tests (#100925)

* Cleaning up the fixture plugins

* Adding basic feature test

* renaming to unsecuredSavedObjectsClient (#101215)

* [Cases] RBAC Refactoring audit logging (#100952)

* Refactoring audit logging

* Adding unit tests for authorization classes

* Addressing feedback and adding util tests

* return undefined on empty array

* fixing eslint

* conditional rendering the recently created cases

* Remove unnecessary Array.from

* Cleaning up overview page for permissions

* Fixing log message for attachments

* hiding add to cases button

* Disable the Cases app from the global nav

* Hide the add to cases button from detections

* Fixing merge

* Making progress on removing icons

* Hding edit icons on detail view

* Trying to get connector error msg tests working

* Removing test

* Disable error callouts

* Fixing spacing and removing cases tab one no read

* Adding read only badge

* Cleaning up and adding badge

* Wrapping in use effect

* Default toasting permissions errors

* Removing actions icon on comments

* Addressing feedback

* Fixing type

Co-authored-by: Christos Nasikas <christos.nasikas@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
3 people committed Jun 22, 2021
1 parent 3da2ac8 commit c5e8df0
Show file tree
Hide file tree
Showing 67 changed files with 1,114 additions and 492 deletions.
26 changes: 18 additions & 8 deletions x-pack/plugins/cases/public/components/add_comment/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { TestProviders } from '../../common/mock';

import { CommentRequest, CommentType, SECURITY_SOLUTION_OWNER } from '../../../common';
import { usePostComment } from '../../containers/use_post_comment';
import { AddComment, AddCommentRefObject } from '.';
import { AddComment, AddCommentProps, AddCommentRefObject } from '.';
import { CasesTimelineIntegrationProvider } from '../timeline_context';
import { timelineIntegrationMock } from '../__mock__/timeline';

Expand All @@ -25,10 +25,9 @@ const onCommentSaving = jest.fn();
const onCommentPosted = jest.fn();
const postComment = jest.fn();

const addCommentProps = {
const addCommentProps: AddCommentProps = {
caseId: '1234',
disabled: false,
insertQuote: null,
userCanCrud: true,
onCommentSaving,
onCommentPosted,
showLoading: false,
Expand Down Expand Up @@ -94,11 +93,11 @@ describe('AddComment ', () => {
).toBeTruthy();
});

it('should disable submit button when disabled prop passed', () => {
it('should disable submit button when isLoading is true', () => {
usePostCommentMock.mockImplementation(() => ({ ...defaultPostComment, isLoading: true }));
const wrapper = mount(
<TestProviders>
<AddComment {...{ ...addCommentProps, disabled: true }} />
<AddComment {...addCommentProps} />
</TestProviders>
);

Expand All @@ -107,12 +106,23 @@ describe('AddComment ', () => {
).toBeTruthy();
});

it('should hide the component when the user does not have crud permissions', () => {
usePostCommentMock.mockImplementation(() => ({ ...defaultPostComment, isLoading: true }));
const wrapper = mount(
<TestProviders>
<AddComment {...{ ...addCommentProps, userCanCrud: false }} />
</TestProviders>
);

expect(wrapper.find(`[data-test-subj="add-comment"]`).exists()).toBeFalsy();
});

it('should insert a quote', async () => {
const sampleQuote = 'what a cool quote';
const ref = React.createRef<AddCommentRefObject>();
const wrapper = mount(
<TestProviders>
<AddComment {...{ ...addCommentProps }} ref={ref} />
<AddComment {...addCommentProps} ref={ref} />
</TestProviders>
);

Expand Down Expand Up @@ -143,7 +153,7 @@ describe('AddComment ', () => {
const wrapper = mount(
<TestProviders>
<CasesTimelineIntegrationProvider timelineIntegration={mockTimelineIntegration}>
<AddComment {...{ ...addCommentProps }} />
<AddComment {...addCommentProps} />
</CasesTimelineIntegrationProvider>
</TestProviders>
);
Expand Down
58 changes: 30 additions & 28 deletions x-pack/plugins/cases/public/components/add_comment/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ export interface AddCommentRefObject {
addQuote: (quote: string) => void;
}

interface AddCommentProps {
export interface AddCommentProps {
caseId: string;
disabled?: boolean;
userCanCrud?: boolean;
onCommentSaving?: () => void;
onCommentPosted: (newCase: Case) => void;
showLoading?: boolean;
Expand All @@ -45,7 +45,7 @@ interface AddCommentProps {
export const AddComment = React.memo(
forwardRef<AddCommentRefObject, AddCommentProps>(
(
{ caseId, disabled, onCommentPosted, onCommentSaving, showLoading = true, subCaseId },
{ caseId, userCanCrud, onCommentPosted, onCommentSaving, showLoading = true, subCaseId },
ref
) => {
const owner = useOwnerContext();
Expand Down Expand Up @@ -91,31 +91,33 @@ export const AddComment = React.memo(
return (
<span id="add-comment-permLink">
{isLoading && showLoading && <MySpinner data-test-subj="loading-spinner" size="xl" />}
<Form form={form}>
<UseField
path={fieldName}
component={MarkdownEditorForm}
componentProps={{
idAria: 'caseComment',
isDisabled: isLoading,
dataTestSubj: 'add-comment',
placeholder: i18n.ADD_COMMENT_HELP_TEXT,
bottomRightContent: (
<EuiButton
data-test-subj="submit-comment"
iconType="plusInCircle"
isDisabled={isLoading || disabled}
isLoading={isLoading}
onClick={onSubmit}
size="s"
>
{i18n.ADD_COMMENT}
</EuiButton>
),
}}
/>
<InsertTimeline fieldName="comment" />
</Form>
{userCanCrud && (
<Form form={form}>
<UseField
path={fieldName}
component={MarkdownEditorForm}
componentProps={{
idAria: 'caseComment',
isDisabled: isLoading,
dataTestSubj: 'add-comment',
placeholder: i18n.ADD_COMMENT_HELP_TEXT,
bottomRightContent: (
<EuiButton
data-test-subj="submit-comment"
iconType="plusInCircle"
isDisabled={isLoading}
isLoading={isLoading}
onClick={onSubmit}
size="s"
>
{i18n.ADD_COMMENT}
</EuiButton>
),
}}
/>
<InsertTimeline fieldName="comment" />
</Form>
)}
</span>
);
}
Expand Down
32 changes: 21 additions & 11 deletions x-pack/plugins/cases/public/components/all_cases/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,27 @@ export const CasesTableHeader: FunctionComponent<Props> = ({
wrap={true}
data-test-subj="all-cases-header"
>
<FlexItemDivider grow={false}>
<Count refresh={refresh} />
</FlexItemDivider>
<EuiFlexItem grow={false}>
<NavButtons
actionsErrors={actionsErrors}
configureCasesNavigation={configureCasesNavigation}
createCaseNavigation={createCaseNavigation}
userCanCrud={userCanCrud}
/>
</EuiFlexItem>
{userCanCrud ? (
<>
<FlexItemDivider grow={false}>
<Count refresh={refresh} />
</FlexItemDivider>

<EuiFlexItem grow={false}>
<NavButtons
actionsErrors={actionsErrors}
configureCasesNavigation={configureCasesNavigation}
createCaseNavigation={createCaseNavigation}
/>
</EuiFlexItem>
</>
) : (
// doesn't include the horizontal bar that divides the buttons and other padding since we don't have any buttons
// to the right
<EuiFlexItem>
<Count refresh={refresh} />
</EuiFlexItem>
)}
</EuiFlexGroup>
</CaseHeaderPage>
);
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ interface OwnProps {
actionsErrors: ErrorMessage[];
configureCasesNavigation: CasesNavigation;
createCaseNavigation: CasesNavigation;
userCanCrud: boolean;
}

type Props = OwnProps;
Expand All @@ -26,22 +25,20 @@ export const NavButtons: FunctionComponent<Props> = ({
actionsErrors,
configureCasesNavigation,
createCaseNavigation,
userCanCrud,
}) => (
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<ConfigureCaseButton
configureCasesNavigation={configureCasesNavigation}
label={i18n.CONFIGURE_CASES_BUTTON}
isDisabled={!isEmpty(actionsErrors) || !userCanCrud}
isDisabled={!isEmpty(actionsErrors)}
showToolTip={!isEmpty(actionsErrors)}
msgTooltip={!isEmpty(actionsErrors) ? actionsErrors[0].description : <></>}
titleTooltip={!isEmpty(actionsErrors) ? actionsErrors[0].title : ''}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<LinkButton
isDisabled={!userCanCrud}
fill
onClick={createCaseNavigation.onClick}
href={createCaseNavigation.href}
Expand Down
26 changes: 14 additions & 12 deletions x-pack/plugins/cases/public/components/all_cases/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,21 @@ export const CasesTable: FunctionComponent<CasesTableProps> = ({
<EuiEmptyPrompt
title={<h3>{i18n.NO_CASES}</h3>}
titleSize="xs"
body={i18n.NO_CASES_BODY}
body={userCanCrud ? i18n.NO_CASES_BODY : i18n.NO_CASES_BODY_READ_ONLY}
actions={
<LinkButton
isDisabled={!userCanCrud}
fill
size="s"
onClick={goToCreateCase}
href={createCaseNavigation.href}
iconType="plusInCircle"
data-test-subj="cases-table-add-case"
>
{i18n.ADD_NEW_CASE}
</LinkButton>
userCanCrud && (
<LinkButton
isDisabled={!userCanCrud}
fill
size="s"
onClick={goToCreateCase}
href={createCaseNavigation.href}
iconType="plusInCircle"
data-test-subj="cases-table-add-case"
>
{i18n.ADD_NEW_CASE}
</LinkButton>
)
}
/>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,19 @@ export * from '../../common/translations';
export const NO_CASES = i18n.translate('xpack.cases.caseTable.noCases.title', {
defaultMessage: 'No Cases',
});

export const NO_CASES_BODY = i18n.translate('xpack.cases.caseTable.noCases.body', {
defaultMessage:
'There are no cases to display. Please create a new case or change your filter settings above.',
});

export const NO_CASES_BODY_READ_ONLY = i18n.translate(
'xpack.cases.caseTable.noCases.readonly.body',
{
defaultMessage: 'There are no cases to display. Please change your filter settings above.',
}
);

export const ADD_NEW_CASE = i18n.translate('xpack.cases.caseTable.addNewCase', {
defaultMessage: 'Add New Case',
});
Expand Down
11 changes: 0 additions & 11 deletions x-pack/plugins/cases/public/components/callout/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,7 @@
* 2.0.
*/

import React from 'react';
import md5 from 'md5';

import * as i18n from './translations';
import { ErrorMessage } from './types';

export const permissionsReadOnlyErrorMessage: ErrorMessage = {
id: 'read-only-privileges-error',
title: i18n.READ_ONLY_FEATURE_TITLE,
description: <>{i18n.READ_ONLY_FEATURE_MSG}</>,
errorType: 'warning',
};

export const createCalloutId = (ids: string[], delimiter: string = '|'): string =>
md5(ids.join(delimiter));
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,6 @@

import { i18n } from '@kbn/i18n';

export const READ_ONLY_FEATURE_TITLE = i18n.translate('xpack.cases.readOnlyFeatureTitle', {
defaultMessage: 'You cannot open new or update existing cases',
});

export const READ_ONLY_FEATURE_MSG = i18n.translate('xpack.cases.readOnlyFeatureDescription', {
defaultMessage:
'You only have privileges to view cases. If you need to open and update cases, contact your Kibana administrator.',
});

export const DISMISS_CALLOUT = i18n.translate('xpack.cases.dismissErrorsPushServiceCallOutTitle', {
defaultMessage: 'Dismiss',
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,12 @@ interface CaseViewActions {
allCasesNavigation: CasesNavigation;
caseData: Case;
currentExternalIncident: CaseService | null;
disabled?: boolean;
}

const ActionsComponent: React.FC<CaseViewActions> = ({
allCasesNavigation,
caseData,
currentExternalIncident,
disabled = false,
}) => {
// Delete case
const {
Expand All @@ -39,7 +37,6 @@ const ActionsComponent: React.FC<CaseViewActions> = ({
const propertyActions = useMemo(
() => [
{
disabled,
iconType: 'trash',
label: i18n.DELETE_CASE(),
onClick: handleToggleModal,
Expand All @@ -54,7 +51,7 @@ const ActionsComponent: React.FC<CaseViewActions> = ({
]
: []),
],
[disabled, handleToggleModal, currentExternalIncident]
[handleToggleModal, currentExternalIncident]
);

if (isDeleted) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe('CaseActionBar', () => {
onRefresh,
onUpdateField,
currentExternalIncident: null,
userCanCrud: true,
};

beforeEach(() => {
Expand Down
Loading

0 comments on commit c5e8df0

Please sign in to comment.