Skip to content

Commit

Permalink
Removed agent RBAC filters from dashboard queries (#6945)
Browse files Browse the repository at this point in the history
* Fix 4.9.0 changelog (#6933)

* Fix 4.9.0 changelog

* Remove 6519 reverted pull request

* Bump 4.9.0 rev 06 RC1 (#6934)

* Bump 4.9.0 revision 06 RC1

* Format

* Remove allowed agents filter in data source

* Remove getAuthorizedAgent no authorization

* Remove allowedAgents from app state

* Remove useAllowedAgents hook

* Remove allowed agents related actions

* Remove allowed agents in reporting

* Apply prettier

* Remove allowed agents

* Fix unit test

* Revert CHANGELOG

* Update CHANGELOG

---------

Co-authored-by: Federico Rodriguez <[email protected]>
  • Loading branch information
Machi3mfl and asteriscos authored Sep 2, 2024
1 parent 977a347 commit 60dcc23
Show file tree
Hide file tree
Showing 25 changed files with 333 additions and 574 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ All notable changes to the Wazuh app project will be documented in this file.

- Changed the registration id of the Settings application for compatibility with Opensearch Dashboard 2.16.0 [#6938](https:/wazuh/wazuh-dashboard-plugins/pull/6938)

### Removed

- Removed agent RBAC filters from dashboard queries [#6945](https:/wazuh/wazuh-dashboard-plugins/pull/6945)

## Wazuh v4.9.1 - OpenSearch Dashboards 2.13.0 - Revision 00

### Added
Expand Down
Original file line number Diff line number Diff line change
@@ -1,129 +1,130 @@
import { useDataSource } from './use-data-source';
import { renderHook } from '@testing-library/react-hooks';
import {
tDataSourceRepository,
tFilter,
PatternDataSource,
tParsedIndexPattern
import {
tDataSourceRepository,
tFilter,
PatternDataSource,
tParsedIndexPattern,
} from '../index';
import { IndexPatternsService, IndexPattern } from '../../../../../../../src/plugins/data/common';
import {
IndexPatternsService,
IndexPattern,
} from '../../../../../../../src/plugins/data/common';

jest.mock('../../../../kibana-services', () => ({
...(jest.requireActual('../../../../kibana-services') as object),
getDataPlugin: () => ({
// mock indexPatterns getter
indexPatterns: {
get: jest.fn().mockResolvedValue({
fields: {
replaceAll: jest.fn(),
map: jest.fn().mockReturnValue([]),
},
getScriptedFields: jest.fn().mockReturnValue([]),
}),
getFieldsForIndexPattern: jest.fn().mockResolvedValue([]),
updateSavedObject: jest.fn().mockResolvedValue({}),
...(jest.requireActual('../../../../kibana-services') as object),
getDataPlugin: () => ({
// mock indexPatterns getter
indexPatterns: {
get: jest.fn().mockResolvedValue({
fields: {
replaceAll: jest.fn(),
map: jest.fn().mockReturnValue([]),
},
query: {
filterManager: {
getFilters: jest.fn().mockReturnValue([]),
setFilters: jest.fn(),
getUpdates$: jest.fn().mockReturnValue({
subscribe: jest.fn()
})
}
}
}),
getScriptedFields: jest.fn().mockReturnValue([]),
}),
getFieldsForIndexPattern: jest.fn().mockResolvedValue([]),
updateSavedObject: jest.fn().mockResolvedValue({}),
},
query: {
filterManager: {
getFilters: jest.fn().mockReturnValue([]),
setFilters: jest.fn(),
getUpdates$: jest.fn().mockReturnValue({
subscribe: jest.fn(),
}),
},
},
}),
}));

const mockedGetFilters = jest.fn().mockReturnValue([]);

class DataSourceMocked implements PatternDataSource {
constructor(public id: string, public title: string) {
this.id = id;
this.title = title;
}
fields: any[];
patternService: IndexPatternsService;
indexPattern: IndexPattern;
defaultFixedFilters: tFilter[];
filters: tFilter[];
init = jest.fn();
select = jest.fn();
fetch = jest.fn();
getFilters = mockedGetFilters;
setFilters = jest.fn();
getFields = mockedGetFilters
getFixedFilters = mockedGetFilters
getFetchFilters = mockedGetFilters
toJSON(): tParsedIndexPattern {
return {
id: this.id,
title: this.title,
} as tParsedIndexPattern;
}
getClusterManagerFilters = mockedGetFilters
getPinnedAgentFilter = mockedGetFilters
getExcludeManagerFilter = mockedGetFilters
getAllowAgentsFilter = mockedGetFilters
constructor(public id: string, public title: string) {
this.id = id;
this.title = title;
}
fields: any[];
patternService: IndexPatternsService;
indexPattern: IndexPattern;
defaultFixedFilters: tFilter[];
filters: tFilter[];
init = jest.fn();
select = jest.fn();
fetch = jest.fn();
getFilters = mockedGetFilters;
setFilters = jest.fn();
getFields = mockedGetFilters;
getFixedFilters = mockedGetFilters;
getFetchFilters = mockedGetFilters;
toJSON(): tParsedIndexPattern {
return {
id: this.id,
title: this.title,
} as tParsedIndexPattern;
}
getClusterManagerFilters = mockedGetFilters;
getPinnedAgentFilter = mockedGetFilters;
getExcludeManagerFilter = mockedGetFilters;
}

class ExampleRepository implements tDataSourceRepository<tParsedIndexPattern> {
getDefault = jest.fn();
setDefault = jest.fn();
get = jest.fn();
getAll = jest.fn();
getDefault = jest.fn();
setDefault = jest.fn();
get = jest.fn();
getAll = jest.fn();
}

describe('useDataSource hook', () => {
it('shoudl throw ERROR when the repository is not defined', () => {
try {
renderHook(() =>
useDataSource({
DataSource: DataSourceMocked,
repository: undefined as any,
}),
);
} catch (error) {
expect(error).toBeDefined();
expect(error.message).toBe('DataSource and repository are required');
}
});

it('shoudl throw ERROR when the repository is not defined', () => {

try {
renderHook(() => useDataSource({
DataSource: DataSourceMocked,
repository: undefined as any
}));
} catch(error){
expect(error).toBeDefined();
expect(error.message).toBe('DataSource and repository are required');
}

})

it('should throw ERROR when the DataSource is not defined', () => {

try {
renderHook(() => useDataSource({
DataSource: undefined as any,
repository: new ExampleRepository()
}));
} catch(error){
expect(error).toBeDefined();
expect(error.message).toBe('DataSource and repository are required');
}

})

// FIXME:
it.skip('should initialize the hook with only receiving the dataSource and repository', async () => {
const repository = new ExampleRepository();
const indexMocked = {
id: 'test',
title: 'Test'
}
jest.spyOn(repository, 'getAll').mockResolvedValueOnce([indexMocked]);
jest.spyOn(repository, 'getDefault').mockResolvedValueOnce(indexMocked);
const { result, waitForNextUpdate } = renderHook(() => useDataSource({
DataSource: DataSourceMocked,
repository
}));
// wait for the promise to resolve
await waitForNextUpdate();
expect(result.current.isLoading).toBeFalsy();
expect(result.current.dataSource).toBeDefined();
expect(result.current.dataSource?.id).toBe('test');
expect(result.current.dataSource?.title).toBe('Test');
})

it('should throw ERROR when the DataSource is not defined', () => {
try {
renderHook(() =>
useDataSource({
DataSource: undefined as any,
repository: new ExampleRepository(),
}),
);
} catch (error) {
expect(error).toBeDefined();
expect(error.message).toBe('DataSource and repository are required');
}
});

})
// FIXME:
it.skip('should initialize the hook with only receiving the dataSource and repository', async () => {
const repository = new ExampleRepository();
const indexMocked = {
id: 'test',
title: 'Test',
};
jest.spyOn(repository, 'getAll').mockResolvedValueOnce([indexMocked]);
jest.spyOn(repository, 'getDefault').mockResolvedValueOnce(indexMocked);
const { result, waitForNextUpdate } = renderHook(() =>
useDataSource({
DataSource: DataSourceMocked,
repository,
}),
);
// wait for the promise to resolve
await waitForNextUpdate();
expect(result.current.isLoading).toBeFalsy();
expect(result.current.dataSource).toBeDefined();
expect(result.current.dataSource?.id).toBe('test');
expect(result.current.dataSource?.title).toBe('Test');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ class DataSourceMocked implements PatternDataSource {
getClusterManagerFilters = mockedGetFilters;
getPinnedAgentFilter = mockedGetFilters;
getExcludeManagerFilter = mockedGetFilters;
getAllowAgentsFilter = mockedGetFilters;
}

const createFilter = (id: string, value: string, index: string): tFilter => {
Expand Down Expand Up @@ -374,27 +373,6 @@ describe('PatternDataSourceFilterManager', () => {
expect(filter.length).toBe(0);
});

it('should return the filters to fetch the data merging the filters stored and the allowed agents filter', () => {
(store.getState as jest.Mock).mockReturnValue({
appStateReducers: {
allowedAgents: ['001'],
},
});
const filter =
PatternDataSourceFilterManager.getAllowAgentsFilter('index-title');
expect(filter.length).toBe(1);
expect(filter[0].meta.controlledBy).toBe(AUTHORIZED_AGENTS);
});

it('should return the filters to fetch the data merging the filters stored without the allowed agents filter when is not defined', () => {
(store.getState as jest.Mock).mockReturnValue({
appStateReducers: {},
});
const filter =
PatternDataSourceFilterManager.getAllowAgentsFilter('index-title');
expect(filter.length).toBe(0);
});

// FIXME:
it.skip('should return the fixed filters merged with the pinned agent filter when correspond', () => {
// mock store.getState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,47 +40,6 @@ export function getFilterExcludeManager(indexPatternId: string) {
};
}

/**
* Get the filter that restrict the search to the allowed agents
* @param agentsIds
* @param indexPatternId
* @returns
*/
export function getFilterAllowedAgents(
agentsIds: string[],
indexPatternId: string,
) {
const field = AGENT_ID_KEY;
return {
meta: {
index: indexPatternId,
type: 'phrases',
key: field,
value: agentsIds.toString(),
params: agentsIds,
alias: null,
negate: false,
disabled: false,
controlledBy: AUTHORIZED_AGENTS,
},
query: {
bool: {
should: agentsIds.map(id => {
return {
match_phrase: {
[field]: id,
},
};
}),
minimum_should_match: 1,
},
},
$state: {
store: 'appState',
},
};
}

export enum FILTER_OPERATOR {
IS = 'is',
IS_NOT = 'is not',
Expand Down Expand Up @@ -359,23 +318,6 @@ export class PatternDataSourceFilterManager
return [];
}

/**
* Return the allowed agents related to the user permissions to read data from agents in the
API server
*/
static getAllowAgentsFilter(indexPatternId: string): tFilter[] {
const allowedAgents =
store.getState().appStateReducers?.allowedAgents || [];
if (allowedAgents.length > 0) {
const allowAgentsFilter = getFilterAllowedAgents(
allowedAgents,
indexPatternId,
) as tFilter;
return [allowAgentsFilter];
}
return [];
}

/******************************************************************/
/********************** FILTERS FACTORY ***************************/
/******************************************************************/
Expand Down
Loading

0 comments on commit 60dcc23

Please sign in to comment.