Skip to content

Commit

Permalink
Grant access to machine learning features when base privileges are us…
Browse files Browse the repository at this point in the history
…ed (#115444)
  • Loading branch information
XavierM authored Oct 26, 2021
1 parent 1827cf2 commit 852a728
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 33 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/ml/common/types/capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export function getPluginPrivileges() {
];
const privilege = {
app: [PLUGIN_ID, 'kibana'],
excludeFromBasePrivileges: true,
excludeFromBasePrivileges: false,
management: {
insightsAndAlerting: ['jobsListLink'],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
expect(sections).to.have.length(2);
expect(sections[0]).to.eql({
sectionId: 'insightsAndAlerting',
sectionLinks: ['triggersActions'],
sectionLinks: ['triggersActions', 'jobsListLink'],
});
expect(sections[1]).to.eql({
sectionId: 'kibana',
Expand Down
74 changes: 72 additions & 2 deletions x-pack/test/functional/apps/ml/feature_controls/ml_security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await security.user.delete('global_all');
});

it(`doesn't show ml navlink`, async () => {
it(`shows ml navlink`, async () => {
const navLinks = (await appsMenu.readLinks()).map((link) => link.text);
expect(navLinks).not.to.contain('Machine Learning');
expect(navLinks).to.contain('Machine Learning');
});
});

Expand All @@ -103,5 +103,75 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
expect(navLinks).to.contain('Machine Learning');
});
});

describe('ml read', () => {
before(async () => {
await security.role.create('ml_role_read', {
elasticsearch: {
indices: [{ names: ['logstash-*'], privileges: ['read', 'view_index_metadata'] }],
},
kibana: [
{
base: [],
feature: { ml: ['read'], savedObjectsManagement: ['read'] },
spaces: ['*'],
},
],
});

await security.user.create('ml_read_user', {
password: 'ml_read-password',
roles: ['ml_role_read'],
full_name: 'ml read',
});

await PageObjects.security.login('ml_read_user', 'ml_read-password');
});

after(async () => {
await security.role.delete('ml_role_read');
await security.user.delete('ml_read_user');
});

it('shows ML navlink', async () => {
const navLinks = (await appsMenu.readLinks()).map((link) => link.text);
expect(navLinks).to.contain('Machine Learning');
});
});

describe('ml none', () => {
before(async () => {
await security.role.create('ml_role_none', {
elasticsearch: {
indices: [{ names: ['logstash-*'], privileges: ['read', 'view_index_metadata'] }],
},
kibana: [
{
base: [],
feature: { discover: ['read'] },
spaces: ['*'],
},
],
});

await security.user.create('ml_none_user', {
password: 'ml_none-password',
roles: ['ml_role_none'],
full_name: 'ml none',
});

await PageObjects.security.login('ml_none_user', 'ml_none-password');
});

after(async () => {
await security.role.delete('ml_role_none');
await security.user.delete('ml_none_user');
});

it('does NOT show ML navlink', async () => {
const navLinks = (await appsMenu.readLinks()).map((link) => link.text);
expect(navLinks).to.not.contain('Machine Learning');
});
});
});
}
5 changes: 1 addition & 4 deletions x-pack/test/functional/apps/ml/permissions/no_ml_access.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
const PageObjects = getPageObjects(['common', 'error']);
const ml = getService('ml');

const testUsers = [
{ user: USER.ML_UNAUTHORIZED, discoverAvailable: true },
{ user: USER.ML_UNAUTHORIZED_SPACES, discoverAvailable: true },
];
const testUsers = [{ user: USER.ML_UNAUTHORIZED, discoverAvailable: true }];

describe('for user with no ML access', function () {
this.tags(['skipFirefox', 'mlqa']);
Expand Down
42 changes: 29 additions & 13 deletions x-pack/test/functional/services/ml/security_common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export enum USER {
ML_VIEWER_SPACE1 = 'ft_ml_viewer_space1',
ML_VIEWER_ALL_SPACES = 'ft_ml_viewer_all_spaces',
ML_UNAUTHORIZED = 'ft_ml_unauthorized',
ML_UNAUTHORIZED_SPACES = 'ft_ml_unauthorized_spaces',
}

export function MachineLearningSecurityCommonProvider({ getService }: FtrProviderContext) {
Expand Down Expand Up @@ -90,8 +89,7 @@ export function MachineLearningSecurityCommonProvider({ getService }: FtrProvide
elasticsearch: { cluster: [], indices: [], run_as: [] },
kibana: [
{
base: [],
feature: { ml: ['all'], savedObjectsManagement: ['all'] },
base: ['all'],
spaces: ['*'],
},
],
Expand Down Expand Up @@ -123,8 +121,7 @@ export function MachineLearningSecurityCommonProvider({ getService }: FtrProvide
elasticsearch: { cluster: [], indices: [], run_as: [] },
kibana: [
{
base: [],
feature: { ml: ['read'], savedObjectsManagement: ['read'] },
base: ['read'],
spaces: ['*'],
},
],
Expand All @@ -134,6 +131,31 @@ export function MachineLearningSecurityCommonProvider({ getService }: FtrProvide
elasticsearch: { cluster: [], indices: [], run_as: [] },
kibana: [{ base: [], feature: { discover: ['read'] }, spaces: ['default'] }],
},
{
name: 'ft_all_space_ml_none',
elasticsearch: { cluster: [], indices: [], run_as: [] },
kibana: [
{
base: [],
// This role is intended to be used by the "ft_ml_poweruser" and "ft_ml_viewer" users; they should have access to ML by virtue of
// the "machine_learning_admin" and "machine_learning_user" roles. However, a user needs _at least_ one Kibana privilege to log
// into Kibana. This role allows these users to log in, but explicitly omits ML from the feature privileges.
// In addition: several functional tests that use these users also rely on UI elements that are enabled by other Kibana features,
// such as "View in Lens", "Add to Dashboard", and creating anomaly detection rules. These feature privileges are the minimal ones
// necessary to satisfy all of those functional tests.
feature: {
discover: ['read'],
visualize: ['read'],
dashboard: ['all'],
actions: ['all'],
savedObjectsManagement: ['all'],
advancedSettings: ['all'],
indexPatterns: ['all'],
},
spaces: ['*'],
},
],
},
];

const users = [
Expand All @@ -142,7 +164,7 @@ export function MachineLearningSecurityCommonProvider({ getService }: FtrProvide
full_name: 'ML Poweruser',
password: 'mlp001',
roles: [
'kibana_admin',
'ft_all_space_ml_none',
'machine_learning_admin',
'ft_ml_source',
'ft_ml_dest',
Expand Down Expand Up @@ -172,7 +194,7 @@ export function MachineLearningSecurityCommonProvider({ getService }: FtrProvide
full_name: 'ML Viewer',
password: 'mlv001',
roles: [
'kibana_admin',
'ft_all_space_ml_none',
'machine_learning_user',
'ft_ml_source_readonly',
'ft_ml_dest_readonly',
Expand Down Expand Up @@ -200,12 +222,6 @@ export function MachineLearningSecurityCommonProvider({ getService }: FtrProvide
name: 'ft_ml_unauthorized',
full_name: 'ML Unauthorized',
password: 'mlu001',
roles: ['kibana_admin', 'ft_ml_source_readonly'],
},
{
name: 'ft_ml_unauthorized_spaces',
full_name: 'ML Unauthorized',
password: 'mlus001',
roles: ['ft_default_space_ml_none', 'ft_ml_source_readonly'],
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
const PageObjects = getPageObjects(['common', 'error']);
const ml = getService('ml');

const testUsers = [
{ user: USER.ML_UNAUTHORIZED, discoverAvailable: true },
{ user: USER.ML_UNAUTHORIZED_SPACES, discoverAvailable: true },
];
const testUsers = [{ user: USER.ML_UNAUTHORIZED, discoverAvailable: true }];

describe('for user with no ML access', function () {
for (const testUser of testUsers) {
Expand Down
29 changes: 23 additions & 6 deletions x-pack/test/ui_capabilities/security_and_spaces/tests/catalogue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,29 +46,46 @@ export default function catalogueTests({ getService }: FtrProviderContext) {
case 'dual_privileges_all at everything_space': {
expect(uiCapabilities.success).to.be(true);
expect(uiCapabilities.value).to.have.property('catalogue');
// everything except ml, monitoring, and ES features are enabled
// everything except monitoring, and ES features are enabled
const expected = mapValues(
uiCapabilities.value!.catalogue,
(enabled, catalogueId) =>
catalogueId !== 'ml' &&
catalogueId !== 'ml_file_data_visualizer' &&
catalogueId !== 'monitoring' &&
catalogueId !== 'osquery' &&
!esFeatureExceptions.includes(catalogueId)
);
expect(uiCapabilities.value!.catalogue).to.eql(expected);
break;
}
case 'everything_space_all at everything_space':
case 'everything_space_all at everything_space': {
expect(uiCapabilities.success).to.be(true);
expect(uiCapabilities.value).to.have.property('catalogue');
// everything except spaces, monitoring, the enterprise search suite, and ES features are enabled
// (easier to say: all "proper" Kibana features are enabled)
const exceptions = [
'monitoring',
'enterpriseSearch',
'appSearch',
'workplaceSearch',
'spaces',
'osquery',
...esFeatureExceptions,
];
const expected = mapValues(
uiCapabilities.value!.catalogue,
(enabled, catalogueId) => !exceptions.includes(catalogueId)
);
expect(uiCapabilities.value!.catalogue).to.eql(expected);
break;
}
case 'global_read at everything_space':
case 'dual_privileges_read at everything_space':
case 'everything_space_read at everything_space': {
expect(uiCapabilities.success).to.be(true);
expect(uiCapabilities.value).to.have.property('catalogue');
// everything except spaces, ml, monitoring, the enterprise search suite, and ES features are enabled
// everything except spaces, ml_file_data_visualizer, monitoring, the enterprise search suite, and ES features are enabled
// (easier to say: all "proper" Kibana features are enabled)
const exceptions = [
'ml',
'ml_file_data_visualizer',
'monitoring',
'enterpriseSearch',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default function navLinksTests({ getService }: FtrProviderContext) {
expect(uiCapabilities.success).to.be(true);
expect(uiCapabilities.value).to.have.property('navLinks');
expect(uiCapabilities.value!.navLinks).to.eql(
navLinksBuilder.except('ml', 'monitoring', 'osquery')
navLinksBuilder.except('monitoring', 'osquery')
);
break;
case 'everything_space_all at everything_space':
Expand All @@ -53,7 +53,6 @@ export default function navLinksTests({ getService }: FtrProviderContext) {
expect(uiCapabilities.value).to.have.property('navLinks');
expect(uiCapabilities.value!.navLinks).to.eql(
navLinksBuilder.except(
'ml',
'monitoring',
'enterpriseSearch',
'appSearch',
Expand Down

0 comments on commit 852a728

Please sign in to comment.