Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Saved Object Aggregation View] Use namespace registry to add tenant filter #1169

Merged
merged 16 commits into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions public/apps/configuration/utils/tenant-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,33 @@ export function transformRoleTenantPermissions(
}));
}

export function getNamespacesToRegister(accountInfo: any) {
const tenants = accountInfo.tenants || {};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cliu123 I noticed when testing this change that the following data structure comes out as:

{
    "global_tenant": true,
    "admin_tenant": true,
    "admin": true
}

Will the values in this map of tenants ever contain false? If so, should this skip over the tenants where the value in this object is false?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cwperks You might have logged in as admin, then you are expected to have all tenant permissions. If you create a role, grant permission to a specific tenant, create a user, map the role to the user, and log in as the user, then you'll see the difference.

const availableTenantNames = Object.keys(tenants!);
const namespacesToRegister = availableTenantNames.map((tenant) => {
if (tenant === globalTenantName) {
return {
id: GLOBAL_USER_DICT.Value,
name: GLOBAL_USER_DICT.Label,
};
} else if (tenant === accountInfo.user_name) {
return {
id: `${PRIVATE_USER_DICT.Value}${accountInfo.user_name}`,
name: PRIVATE_USER_DICT.Label,
};
}
return {
id: tenant,
name: tenant,
};
});
namespacesToRegister.push({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will always include default in the dropdown. default comes into play when OSD deployments with existing saved objects enable the saved object aggregation view feature. These objects do not have the namespace of the saved object populated and will be given the default (or null) namespace.

id: DEFAULT_TENANT,
name: DEFAULT_TENANT,
});
return namespacesToRegister;
}

export function isPrivateTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant === PRIVATE_TENANT_SYMBOL;
}
Expand Down
60 changes: 60 additions & 0 deletions public/apps/configuration/utils/test/tenant-utils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
transformRoleTenantPermissionData,
getTenantPermissionType,
transformRoleTenantPermissions,
getNamespacesToRegister,
} from '../tenant-utils';
import {
RoleViewTenantInvalidText,
Expand Down Expand Up @@ -282,4 +283,63 @@ describe('Tenant list utils', () => {
expect(result[0]).toMatchObject(expectedRoleTenantPermissionView);
});
});

describe('get list of namespaces to register', () => {
it('resolves to list of namespaces with a custom tenant', () => {
const authInfo = {
'user_name': 'user1',
'tenants': {
'global_tenant': true,
'user1_tenant': true,
'user1': true,
},
}
const expectedNamespaces = [
{
'id': GLOBAL_USER_DICT.Value,
'name': GLOBAL_USER_DICT.Label,
},
{
'id': 'user1_tenant',
'name': 'user1_tenant',
},
{
'id': `${PRIVATE_USER_DICT.Value}user1`,
'name': PRIVATE_USER_DICT.Label,
},
{
'id': 'default',
'name': 'default',
}
];
const result = getNamespacesToRegister(authInfo);
expect(result).toMatchObject(expectedNamespaces);
});

it('resolves to list of namespaces without a custom tenant', () => {
const authInfo = {
'user_name': 'user1',
'tenants': {
'global_tenant': true,
'user1': true,
},
}
const expectedNamespaces = [
{
'id': GLOBAL_USER_DICT.Value,
'name': GLOBAL_USER_DICT.Label,
},
{
'id': `${PRIVATE_USER_DICT.Value}user1`,
'name': PRIVATE_USER_DICT.Label,
},
{
'id': 'default',
'name': 'default',
}
];
const result = getNamespacesToRegister(authInfo);
expect(result).toMatchObject(expectedNamespaces);
});
});
});
9 changes: 8 additions & 1 deletion public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import {
} from './types';
import { addTenantToShareURL } from './services/shared-link';
import { interceptError } from './utils/logout-utils';
import { tenantColumn } from './apps/configuration/utils/tenant-utils';
import { tenantColumn, getNamespacesToRegister } from './apps/configuration/utils/tenant-utils';

async function hasApiPermission(core: CoreSetup): Promise<boolean | undefined> {
try {
Expand Down Expand Up @@ -157,6 +157,13 @@ export class SecurityPlugin
deps.savedObjectsManagement.columns.register(
(tenantColumn as unknown) as SavedObjectsManagementColumn<string>
);
if (!!accountInfo) {
const namespacesToRegister = getNamespacesToRegister(accountInfo);
deps.savedObjectsManagement.namespaces.registerAlias("Tenant");
namespacesToRegister.forEach((ns) => {
deps.savedObjectsManagement.namespaces.register(ns as SavedObjectsManagementNamespace);
});
}
}

// Return methods that should be available to other plugins
Expand Down
9 changes: 7 additions & 2 deletions server/saved_objects/saved_objects_wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,14 @@ export class SecuritySavedObjectsClientWrapper {
typeToNamespacesMap[t] = availableTenantNames;
}
});
if ('config' in typeToNamespacesMap) {
typeToNamespacesMap.config = [namespaceValue];
if (searchTypes.includes('config')) {
if (!options.namespaces || options.namespaces.includes(namespaceValue)) {
typeToNamespacesMap.config = [namespaceValue];
} else {
delete typeToNamespacesMap.config
}
}

options.typeToNamespacesMap = new Map(Object.entries(typeToNamespacesMap));
options.type = '';
options.namespaces = [];
Expand Down