Skip to content

Commit

Permalink
Merge branch 'main' into add_ml
Browse files Browse the repository at this point in the history
  • Loading branch information
cliu123 authored Nov 3, 2022
2 parents 6de7930 + 24807bb commit fe07f57
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 47 deletions.
19 changes: 19 additions & 0 deletions common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ export const AUTH_HEADER_NAME = 'authorization';
export const AUTH_GRANT_TYPE = 'authorization_code';
export const AUTH_RESPONSE_TYPE = 'code';

export const GLOBAL_TENANT_SYMBOL = '';
export const PRIVATE_TENANT_SYMBOL = '__user__';
export const DEFAULT_TENANT = 'default';
export const GLOBAL_TENANT_RENDERING_TEXT = 'Global';
export const PRIVATE_TENANT_RENDERING_TEXT = 'Private';
export const globalTenantName = 'global_tenant';

export enum AuthType {
BASIC = 'basicauth',
OPEN_ID = 'openid',
Expand All @@ -61,3 +68,15 @@ export function isValidResourceName(resourceName: string): boolean {
const exp = new RegExp('[\\p{C}%]', 'u');
return !exp.test(resourceName) && resourceName.length > 0;
}

export function isPrivateTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant === PRIVATE_TENANT_SYMBOL;
}

export function isRenderingPrivateTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant?.startsWith(PRIVATE_TENANT_SYMBOL);
}

export function isGlobalTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant === GLOBAL_TENANT_SYMBOL;
}
66 changes: 42 additions & 24 deletions public/apps/configuration/utils/tenant-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,34 @@ import { map } from 'lodash';
import React from 'react';
import { i18n } from '@osd/i18n';
import {
API_ENDPOINT_TENANTS,
API_ENDPOINT_MULTITENANCY,
API_ENDPOINT_TENANTS,
RoleViewTenantInvalidText,
TENANT_READ_PERMISSION,
TENANT_WRITE_PERMISSION,
} from '../constants';
import {
DataObject,
ObjectsMessage,
Tenant,
TenantUpdate,
TenantSelect,
RoleTenantPermissionView,
RoleTenantPermission,
RoleTenantPermissionDetail,
RoleTenantPermissionView,
Tenant,
TenantPermissionType,
RoleTenantPermission,
TenantSelect,
TenantUpdate,
} from '../types';
import { TENANT_READ_PERMISSION, TENANT_WRITE_PERMISSION } from '../constants';
import { httpDelete, httpGet, httpPost } from './request-utils';
import { getResourceUrl } from './resource-utils';

export const globalTenantName = 'global_tenant';
export const GLOBAL_TENANT_SYMBOL = '';
export const PRIVATE_TENANT_SYMBOL = '__user__';
export const DEFAULT_TENANT = 'default';
export const GLOBAL_TENANT_RENDERING_TEXT = 'Global';
export const PRIVATE_TENANT_RENDERING_TEXT = 'Private';
import {
DEFAULT_TENANT,
GLOBAL_TENANT_RENDERING_TEXT,
GLOBAL_TENANT_SYMBOL,
globalTenantName,
isGlobalTenant,
isRenderingPrivateTenant,
PRIVATE_TENANT_RENDERING_TEXT,
} from '../../../../common';

export const GLOBAL_USER_DICT: { [key: string]: string } = {
Label: 'Global',
Expand Down Expand Up @@ -179,16 +182,31 @@ export function transformRoleTenantPermissions(
}));
}

export function isPrivateTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant === PRIVATE_TENANT_SYMBOL;
}

export function isRenderingPrivateTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant?.startsWith(PRIVATE_TENANT_SYMBOL);
}

export function isGlobalTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant === GLOBAL_TENANT_SYMBOL;
export function getNamespacesToRegister(accountInfo: any) {
const tenants = accountInfo.tenants || {};
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({
id: DEFAULT_TENANT,
name: DEFAULT_TENANT,
});
return namespacesToRegister;
}

export const tenantColumn = {
Expand Down
62 changes: 61 additions & 1 deletion public/apps/configuration/utils/test/tenant-utils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,19 @@ import {
resolveTenantName,
RESOLVED_GLOBAL_TENANT,
RESOLVED_PRIVATE_TENANT,
globalTenantName,
formatTenantName,
transformRoleTenantPermissionData,
getTenantPermissionType,
transformRoleTenantPermissions,
getNamespacesToRegister,
} from '../tenant-utils';
import {
RoleViewTenantInvalidText,
TENANT_READ_PERMISSION,
TENANT_WRITE_PERMISSION,
} from '../../constants';
import { TenantPermissionType } from '../../types';
import { globalTenantName } from '../../../../../common';

describe('Tenant list utils', () => {
const expectedGlobalTenantListing = {
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
2 changes: 1 addition & 1 deletion server/auth/types/authentication_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { SecuritySessionCookie } from '../../session/security_cookie';
import { SecurityClient } from '../../backend/opensearch_security_client';
import { resolveTenant, isValidTenant } from '../../multitenancy/tenant_resolver';
import { UnauthenticatedError } from '../../errors';
import { GLOBAL_TENANT_SYMBOL } from '../../../public/apps/configuration/utils/tenant-utils';
import { GLOBAL_TENANT_SYMBOL } from '../../../common';

export interface IAuthenticationType {
type: string;
Expand Down
5 changes: 1 addition & 4 deletions server/multitenancy/tenant_resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ import { isEmpty, findKey, cloneDeep } from 'lodash';
import { OpenSearchDashboardsRequest } from '../../../../src/core/server';
import { SecuritySessionCookie } from '../session/security_cookie';
import { SecurityPluginConfigType } from '..';
import {
GLOBAL_TENANT_SYMBOL,
PRIVATE_TENANT_SYMBOL,
} from '../../public/apps/configuration/utils/tenant-utils';
import { GLOBAL_TENANT_SYMBOL, PRIVATE_TENANT_SYMBOL } from '../../common';

export const PRIVATE_TENANTS: string[] = [PRIVATE_TENANT_SYMBOL, 'private'];
export const GLOBAL_TENANTS: string[] = ['global', GLOBAL_TENANT_SYMBOL];
Expand Down
40 changes: 24 additions & 16 deletions server/saved_objects/saved_objects_wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ import {
} from 'opensearch-dashboards/server';
import { Config } from 'packages/osd-config/target';
import { SecurityPluginConfigType } from '..';
import { OpenSearchDashboardsAuthState } from '../auth/types/authentication_type';
import {
DEFAULT_TENANT,
globalTenantName,
GLOBAL_TENANT_SYMBOL,
globalTenantName,
isPrivateTenant,
PRIVATE_TENANT_SYMBOL,
} from '../../public/apps/configuration/utils/tenant-utils';
import { OpenSearchDashboardsAuthState } from '../auth/types/authentication_type';
} from '../../common';

export class SecuritySavedObjectsClientWrapper {
public httpStart?: HttpServiceStart;
Expand Down Expand Up @@ -104,24 +104,32 @@ export class SecuritySavedObjectsClientWrapper {
availableTenantNames.splice(index, 1);
}
}
const typeToNamespacesMap: any = {};
if (isPrivateTenant(selectedTenant!)) {
namespaceValue = selectedTenant! + username;
}
const searchTypes = Array.isArray(options.type) ? options.type : [options.type];
searchTypes.forEach((t) => {
if ('namespaces' in options) {
typeToNamespacesMap[t] = options.namespaces;
} else {
typeToNamespacesMap[t] = availableTenantNames;
if (!!options.namespaces) {
const namespacesToInclude = Array.isArray(options.namespaces)
? options.namespaces
: [options.namespaces];
const typeToNamespacesMap: any = {};
const searchTypes = Array.isArray(options.type) ? options.type : [options.type];
searchTypes.forEach((t) => {
typeToNamespacesMap[t] = namespacesToInclude;
});
if (searchTypes.includes('config')) {
if (namespacesToInclude.includes(namespaceValue)) {
typeToNamespacesMap.config = [namespaceValue];
} else {
delete typeToNamespacesMap.config;
}
}
});
if ('config' in typeToNamespacesMap) {
typeToNamespacesMap.config = [namespaceValue];

options.typeToNamespacesMap = new Map(Object.entries(typeToNamespacesMap));
options.type = '';
options.namespaces = [];
} else {
options.namespaces = [namespaceValue];
}
options.typeToNamespacesMap = new Map(Object.entries(typeToNamespacesMap));
options.type = '';
options.namespaces = [];

return await wrapperOptions.client.find(options);
};
Expand Down

0 comments on commit fe07f57

Please sign in to comment.