Files
2024-12-10 11:32:27 +00:00

190 lines
8.0 KiB
TypeScript

import {
AzureCredentials,
AzureCloud,
ConcealedSecret,
AzureClientSecretCredentials,
instanceOfAzureCredential,
updateDatasourceCredentials,
} from '@grafana/azure-sdk';
import { config } from '@grafana/runtime';
import {
dataSourceSettingsWithMsiCredentials,
dataSourceSettingsWithClientSecretOnServer,
dataSourceSettingsWithClientSecretInSecureJSONData,
} from './AzureAuth.testMocks';
import { getDefaultCredentials, getCredentials } from './AzureCredentialsConfig';
// NOTE: @ts-ignores are used to ignore the type errors that are thrown when passing in the mocks.
// This is because the mocks are partials of the actual types, so the types are not complete.
export const CLIENT_SECRET_SYMBOL: ConcealedSecret = Symbol('Concealed client secret');
export const CLIENT_SECRET_STRING = 'XXXX-super-secret-secret-XXXX';
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'), // Keep the rest of the actual module
}));
describe('AzureAuth', () => {
beforeEach(() => {
jest.resetModules();
});
describe('AzureCredentialsConfig', () => {
it('`getDefaultCredentials()` should return the correct credentials based on whether the managed identity is enabled', () => {
jest.mocked(config).azure.managedIdentityEnabled = true;
const resultForManagedIdentityEnabled = getDefaultCredentials();
jest.mocked(config).azure.managedIdentityEnabled = false;
const resultForManagedIdentityDisabled = getDefaultCredentials();
expect(resultForManagedIdentityEnabled).toEqual({ authType: 'msi' });
expect(resultForManagedIdentityDisabled).toEqual({ authType: 'clientsecret', azureCloud: 'AzureCloud' });
});
describe('getCredentials()', () => {
it('should return the correct managed identity credentials', () => {
// If `dataSourceSettings.authType === 'msi'` && `config.azure.managedIdentityEnabled === true`.
jest.mocked(config).azure.managedIdentityEnabled = true;
const resultForManagedIdentityEnabled = getCredentials(
// @ts-ignore
dataSourceSettingsWithMsiCredentials
);
expect(resultForManagedIdentityEnabled).toEqual({ authType: 'msi' });
// If `dataSourceSettings.authType === 'msi'` but `config.azure.managedIdentityEnabled !== true`.
// Default to basic client secret credentials.
jest.mocked(config).azure.managedIdentityEnabled = false;
const resultForManagedIdentityEnabledInJSONButDisabledInConfig = getCredentials(
// @ts-ignore
dataSourceSettingsWithMsiCredentials
);
expect(resultForManagedIdentityEnabledInJSONButDisabledInConfig).toEqual({
authType: 'clientsecret',
azureCloud: 'AzureCloud',
});
});
it('should return the correct client secret credentials', () => {
const basicExpectedResult = {
authType: 'clientsecret',
azureCloud: 'AzureCloud',
tenantId: 'XXXX-tenant-id-XXXX',
clientId: 'XXXX-client-id-XXXX',
};
// If `dataSourceSettings.authType === 'clientsecret'` && `secureJsonFields.azureClientSecret == true`,
// i.e. the client secret is stored on the server.
jest.mocked(config).azure.managedIdentityEnabled = false;
const resultForClientSecretCredentialsOnServer = getCredentials(
// @ts-ignore
dataSourceSettingsWithClientSecretOnServer
);
// Here we test the properties separately because the client secret is a symbol,
// and since JS symobls are unique, we test via the `typeof` operator.
expect(resultForClientSecretCredentialsOnServer.authType).toEqual('clientsecret');
expect(
instanceOfAzureCredential<AzureClientSecretCredentials>(
'clientsecret',
resultForClientSecretCredentialsOnServer
)
).toEqual(true);
expect((resultForClientSecretCredentialsOnServer as AzureClientSecretCredentials).azureCloud).toEqual(
'AzureCloud'
);
expect((resultForClientSecretCredentialsOnServer as AzureClientSecretCredentials).tenantId).toEqual(
'XXXX-tenant-id-XXXX'
);
expect((resultForClientSecretCredentialsOnServer as AzureClientSecretCredentials).clientId).toEqual(
'XXXX-client-id-XXXX'
);
expect(typeof (resultForClientSecretCredentialsOnServer as AzureClientSecretCredentials).clientSecret).toEqual(
'symbol'
);
// If `dataSourceSettings.authType === 'clientsecret'` && `secureJsonFields.azureClientSecret == false`,
// i.e. the client secret is stored in the secureJson.
jest.mocked(config).azure.managedIdentityEnabled = false;
const resultForClientSecretCredentialsInSecureJSON = getCredentials(
// @ts-ignore
dataSourceSettingsWithClientSecretInSecureJSONData
);
expect(resultForClientSecretCredentialsInSecureJSON).toEqual({
...basicExpectedResult,
clientSecret: CLIENT_SECRET_STRING,
});
});
});
describe('updateCredentials()', () => {
it('should update the credentials for managed service identity correctly', () => {
// If `dataSourceSettings.authType === 'msi'` && `config.azure.managedIdentityEnabled === true`.
jest.mocked(config).azure.managedIdentityEnabled = true;
const resultForMsiCredentials = updateDatasourceCredentials(
// @ts-ignore
dataSourceSettingsWithMsiCredentials,
{
authType: 'msi',
}
);
expect(resultForMsiCredentials).toEqual({ jsonData: { azureCredentials: { authType: 'msi' } } });
// If `dataSourceSettings.authType === 'msi'` but `config.azure.managedIdentityEnabled !== true`.
jest.mocked(config).azure.managedIdentityEnabled = false;
expect(() =>
updateDatasourceCredentials(
// @ts-ignore
dataSourceSettingsWithMsiCredentials,
{
authType: 'msi',
}
)
).toThrow('Managed Identity authentication is not enabled in Grafana config.');
});
it('should update the credentials for client secret correctly', () => {
const basicClientSecretCredentials: AzureCredentials = {
authType: 'clientsecret',
azureCloud: AzureCloud.Public,
tenantId: 'XXXX-tenant-id-XXXX',
clientId: 'XXXX-client-id-XXXX',
};
// If `dataSourceSettings.authType === 'clientsecret'` && `secureJsonFields.azureClientSecret == true`.
jest.mocked(config).azure.managedIdentityEnabled = false;
const resultForClientSecretCredentials1 = updateDatasourceCredentials(
// @ts-ignore
dataSourceSettingsWithClientSecretOnServer,
basicClientSecretCredentials
);
expect(resultForClientSecretCredentials1.jsonData.azureCredentials).toEqual(basicClientSecretCredentials);
expect(resultForClientSecretCredentials1.secureJsonData).toEqual({ azureClientSecret: undefined });
expect(resultForClientSecretCredentials1.secureJsonFields).toEqual({
azureClientSecret: false,
clientSecret: false,
});
// If `dataSourceSettings.authType === 'clientsecret'` && `secureJsonFields.azureClientSecret == false`.
jest.mocked(config).azure.managedIdentityEnabled = false;
const resultForClientSecretCredentials2 = updateDatasourceCredentials(
// @ts-ignore
dataSourceSettingsWithClientSecretInSecureJSONData,
{ ...basicClientSecretCredentials, clientSecret: 'XXXX-super-secret-secret-XXXX' }
);
expect(resultForClientSecretCredentials2.jsonData.azureCredentials).toEqual(basicClientSecretCredentials);
expect(resultForClientSecretCredentials2.secureJsonData).toEqual({
azureClientSecret: 'XXXX-super-secret-secret-XXXX',
});
expect(resultForClientSecretCredentials2.secureJsonFields).toEqual({
azureClientSecret: false,
clientSecret: false,
});
});
});
});
});