-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[SECURITY] Add Privilege deprecations services in security plugin (#1…
…13151) * non-working POC for privilege deprecations * wip to be bale to deprecated sub feature case in security solutions * finalyze deprecations of cases sub feature in security solutions * only adding the deprecation servces in security * add test + translation * Update x-pack/plugins/security/server/deprecations/privilege_deprecations.ts Co-authored-by: Joe Portner <5295965+jportner@users.noreply.github.com> * joe reviews * renaming + double check Co-authored-by: Larry Gregory <larry.gregory@elastic.co> Co-authored-by: Joe Portner <5295965+jportner@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
- Loading branch information
1 parent
141a88b
commit 77675d9
Showing
13 changed files
with
464 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths | ||
import type { DeprecationsDetails, GetDeprecationsContext } from '../../../../../src/core/server'; | ||
import type { Role } from './role'; | ||
|
||
export interface PrivilegeDeprecationsRolesByFeatureIdResponse { | ||
roles?: Role[]; | ||
errors?: DeprecationsDetails[]; | ||
} | ||
|
||
export interface PrivilegeDeprecationsRolesByFeatureIdRequest { | ||
context: GetDeprecationsContext; | ||
featureId: string; | ||
} | ||
export interface PrivilegeDeprecationsService { | ||
getKibanaRolesByFeatureId: ( | ||
args: PrivilegeDeprecationsRolesByFeatureIdRequest | ||
) => Promise<PrivilegeDeprecationsRolesByFeatureIdResponse>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
export { transformElasticsearchRoleToRole, ElasticsearchRole } from './elasticsearch_role'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
/** | ||
* getKibanaRolesByFeature | ||
*/ | ||
|
||
export { getPrivilegeDeprecationsService } from './privilege_deprecations'; |
284 changes: 284 additions & 0 deletions
284
x-pack/plugins/security/server/deprecations/privilege_deprecations.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,284 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import type { GetDeprecationsContext } from 'src/core/server'; | ||
import { elasticsearchServiceMock, loggingSystemMock } from 'src/core/server/mocks'; | ||
|
||
import { getPrivilegeDeprecationsService } from '.'; | ||
import { licenseMock } from '../../common/licensing/index.mock'; | ||
|
||
const kibanaIndexName = '.a-kibana-index'; | ||
const application = `kibana-${kibanaIndexName}`; | ||
|
||
describe('#getPrivilegeDeprecationsService', () => { | ||
describe('#getKibanaRolesByFeatureId', () => { | ||
const mockAsCurrentUser = elasticsearchServiceMock.createScopedClusterClient(); | ||
const mockLicense = licenseMock.create(); | ||
const mockLogger = loggingSystemMock.createLogger(); | ||
const authz = { applicationName: application }; | ||
|
||
const { getKibanaRolesByFeatureId } = getPrivilegeDeprecationsService( | ||
authz, | ||
mockLicense, | ||
mockLogger | ||
); | ||
|
||
it('happy path to find siem roles with feature_siem privileges', async () => { | ||
mockAsCurrentUser.asCurrentUser.security.getRole.mockResolvedValue( | ||
elasticsearchServiceMock.createSuccessTransportRequestPromise({ | ||
first_role: { | ||
cluster: [], | ||
indices: [], | ||
applications: [ | ||
{ | ||
application, | ||
privileges: ['feature_siem.all', 'feature_siem.cases_read'], | ||
resources: ['space:securitySolutions'], | ||
}, | ||
], | ||
run_as: [], | ||
metadata: { | ||
_reserved: true, | ||
}, | ||
transient_metadata: { | ||
enabled: true, | ||
}, | ||
}, | ||
}) | ||
); | ||
|
||
const mockContext = { | ||
esClient: mockAsCurrentUser, | ||
savedObjectsClient: jest.fn(), | ||
} as unknown as GetDeprecationsContext; | ||
|
||
const resp = await getKibanaRolesByFeatureId({ context: mockContext, featureId: 'siem' }); | ||
expect(resp).toMatchInlineSnapshot(` | ||
Object { | ||
"roles": Array [ | ||
Object { | ||
"_transform_error": Array [], | ||
"_unrecognized_applications": Array [], | ||
"elasticsearch": Object { | ||
"cluster": Array [], | ||
"indices": Array [], | ||
"run_as": Array [], | ||
}, | ||
"kibana": Array [ | ||
Object { | ||
"base": Array [], | ||
"feature": Object { | ||
"siem": Array [ | ||
"all", | ||
"cases_read", | ||
], | ||
}, | ||
"spaces": Array [ | ||
"securitySolutions", | ||
], | ||
}, | ||
], | ||
"metadata": Object { | ||
"_reserved": true, | ||
}, | ||
"name": "first_role", | ||
"transient_metadata": Object { | ||
"enabled": true, | ||
}, | ||
}, | ||
], | ||
} | ||
`); | ||
}); | ||
|
||
it('happy path to find siem roles with feature_siem and feature_foo and feature_bar privileges', async () => { | ||
mockAsCurrentUser.asCurrentUser.security.getRole.mockResolvedValue( | ||
elasticsearchServiceMock.createSuccessTransportRequestPromise({ | ||
first_role: { | ||
cluster: [], | ||
indices: [], | ||
applications: [ | ||
{ | ||
application, | ||
privileges: [ | ||
'feature_foo.foo-privilege-1', | ||
'feature_foo.foo-privilege-2', | ||
'feature_bar.bar-privilege-1', | ||
'feature_siem.all', | ||
'feature_siem.cases_read', | ||
], | ||
resources: ['space:securitySolutions'], | ||
}, | ||
], | ||
run_as: [], | ||
metadata: { | ||
_reserved: true, | ||
}, | ||
transient_metadata: { | ||
enabled: true, | ||
}, | ||
}, | ||
}) | ||
); | ||
|
||
const mockContext = { | ||
esClient: mockAsCurrentUser, | ||
savedObjectsClient: jest.fn(), | ||
} as unknown as GetDeprecationsContext; | ||
|
||
const resp = await getKibanaRolesByFeatureId({ context: mockContext, featureId: 'siem' }); | ||
expect(resp).toMatchInlineSnapshot(` | ||
Object { | ||
"roles": Array [ | ||
Object { | ||
"_transform_error": Array [], | ||
"_unrecognized_applications": Array [], | ||
"elasticsearch": Object { | ||
"cluster": Array [], | ||
"indices": Array [], | ||
"run_as": Array [], | ||
}, | ||
"kibana": Array [ | ||
Object { | ||
"base": Array [], | ||
"feature": Object { | ||
"bar": Array [ | ||
"bar-privilege-1", | ||
], | ||
"foo": Array [ | ||
"foo-privilege-1", | ||
"foo-privilege-2", | ||
], | ||
"siem": Array [ | ||
"all", | ||
"cases_read", | ||
], | ||
}, | ||
"spaces": Array [ | ||
"securitySolutions", | ||
], | ||
}, | ||
], | ||
"metadata": Object { | ||
"_reserved": true, | ||
}, | ||
"name": "first_role", | ||
"transient_metadata": Object { | ||
"enabled": true, | ||
}, | ||
}, | ||
], | ||
} | ||
`); | ||
}); | ||
|
||
it('happy path to NOT find siem roles with and feature_foo and feature_bar privileges', async () => { | ||
mockAsCurrentUser.asCurrentUser.security.getRole.mockResolvedValue( | ||
elasticsearchServiceMock.createSuccessTransportRequestPromise({ | ||
first_role: { | ||
cluster: [], | ||
indices: [], | ||
applications: [ | ||
{ | ||
application, | ||
privileges: [ | ||
'feature_foo.foo-privilege-1', | ||
'feature_foo.foo-privilege-2', | ||
'feature_bar.bar-privilege-1', | ||
], | ||
resources: ['space:securitySolutions'], | ||
}, | ||
], | ||
run_as: [], | ||
metadata: { | ||
_reserved: true, | ||
}, | ||
transient_metadata: { | ||
enabled: true, | ||
}, | ||
}, | ||
}) | ||
); | ||
|
||
const mockContext = { | ||
esClient: mockAsCurrentUser, | ||
savedObjectsClient: jest.fn(), | ||
} as unknown as GetDeprecationsContext; | ||
|
||
const resp = await getKibanaRolesByFeatureId({ context: mockContext, featureId: 'siem' }); | ||
expect(resp).toMatchInlineSnapshot(` | ||
Object { | ||
"roles": Array [], | ||
} | ||
`); | ||
}); | ||
|
||
it('unhappy path with status code 400, we should have the attribute errors', async () => { | ||
mockAsCurrentUser.asCurrentUser.security.getRole.mockResolvedValue( | ||
elasticsearchServiceMock.createErrorTransportRequestPromise({ | ||
message: 'Test error', | ||
statusCode: 400, | ||
}) | ||
); | ||
|
||
const mockContext = { | ||
esClient: mockAsCurrentUser, | ||
savedObjectsClient: jest.fn(), | ||
} as unknown as GetDeprecationsContext; | ||
|
||
const resp = await getKibanaRolesByFeatureId({ context: mockContext, featureId: 'siem' }); | ||
expect(resp).toMatchInlineSnapshot(` | ||
Object { | ||
"errors": Array [ | ||
Object { | ||
"correctiveActions": Object { | ||
"manualSteps": Array [ | ||
"A user with the \\"manage_security\\" cluster privilege is required to perform this check.", | ||
], | ||
}, | ||
"level": "fetch_error", | ||
"message": "Error retrieving roles for privilege deprecations: Test error", | ||
"title": "Error in privilege deprecations services", | ||
}, | ||
], | ||
} | ||
`); | ||
}); | ||
|
||
it('unhappy path with status code 403, we should have unauthorized message in the attribute errors', async () => { | ||
mockAsCurrentUser.asCurrentUser.security.getRole.mockResolvedValue( | ||
elasticsearchServiceMock.createErrorTransportRequestPromise({ | ||
message: 'Test error', | ||
statusCode: 403, | ||
}) | ||
); | ||
|
||
const mockContext = { | ||
esClient: mockAsCurrentUser, | ||
savedObjectsClient: jest.fn(), | ||
} as unknown as GetDeprecationsContext; | ||
|
||
const resp = await getKibanaRolesByFeatureId({ context: mockContext, featureId: 'siem' }); | ||
expect(resp).toMatchInlineSnapshot(` | ||
Object { | ||
"errors": Array [ | ||
Object { | ||
"correctiveActions": Object { | ||
"manualSteps": Array [ | ||
"A user with the \\"manage_security\\" cluster privilege is required to perform this check.", | ||
], | ||
}, | ||
"level": "fetch_error", | ||
"message": "You must have the 'manage_security' cluster privilege to fix role deprecations.", | ||
"title": "Error in privilege deprecations services", | ||
}, | ||
], | ||
} | ||
`); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.