mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[8.12] [Response Ops][Actions] Adding configuration to override default MS Graph API Scope and Exchange URL values (#175812) (#176085)
# Backport This will backport the following commits from `main` to `8.12`: - [[Response Ops][Actions] Adding configuration to override default MS Graph API Scope and Exchange URL values (#175812)](https://github.com/elastic/kibana/pull/175812) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Ying Mao","email":"ying.mao@elastic.co"},"sourceCommit":{"committedDate":"2024-02-01T17:41:52Z","message":"[Response Ops][Actions] Adding configuration to override default MS Graph API Scope and Exchange URL values (#175812)\n\nResolves https://github.com/elastic/kibana/issues/166064\r\n\r\n## Summary\r\n\r\nAdds the following configurations to the `kibana.yml` config:\r\n* `xpack.actions.microsoftGraphApiScope` - overrides the default Graph\r\nAPI scope value of `https://graph.microsoft.com/.default`\r\n* `xpack.actions.microsoftExchangeUrl` - overrides the default value of\r\n`https://login.microsoftonline.com`\r\n\r\nThis allows users in different Azure environments to customize their\r\nendpoints as needed.\r\n\r\n## To Verify\r\n\r\nWe are unable to test this in a different environment but we can verify\r\nthat the config overrides the defaults as expected by setting the config\r\nvalues to something different and the logging out the params that are\r\nsent to `getOAuthClientCredentialsAccessToken` in\r\n`x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts`.\r\nThen create an MS Exchange email connector and test it to see that the\r\nlogged values are overridden as expected.\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>","sha":"f7e4f7a636763d46cb6a38b21a5eb6e67595ddfe","branchLabelMapping":{"^v8.13.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Feature:Actions","Team:ResponseOps","backport:prev-minor","backport:prev-MAJOR","v8.13.0"],"title":"[Response Ops][Actions] Adding configuration to override default MS Graph API Scope and Exchange URL values","number":175812,"url":"https://github.com/elastic/kibana/pull/175812","mergeCommit":{"message":"[Response Ops][Actions] Adding configuration to override default MS Graph API Scope and Exchange URL values (#175812)\n\nResolves https://github.com/elastic/kibana/issues/166064\r\n\r\n## Summary\r\n\r\nAdds the following configurations to the `kibana.yml` config:\r\n* `xpack.actions.microsoftGraphApiScope` - overrides the default Graph\r\nAPI scope value of `https://graph.microsoft.com/.default`\r\n* `xpack.actions.microsoftExchangeUrl` - overrides the default value of\r\n`https://login.microsoftonline.com`\r\n\r\nThis allows users in different Azure environments to customize their\r\nendpoints as needed.\r\n\r\n## To Verify\r\n\r\nWe are unable to test this in a different environment but we can verify\r\nthat the config overrides the defaults as expected by setting the config\r\nvalues to something different and the logging out the params that are\r\nsent to `getOAuthClientCredentialsAccessToken` in\r\n`x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts`.\r\nThen create an MS Exchange email connector and test it to see that the\r\nlogged values are overridden as expected.\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>","sha":"f7e4f7a636763d46cb6a38b21a5eb6e67595ddfe"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v8.13.0","branchLabelMappingKey":"^v8.13.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/175812","number":175812,"mergeCommit":{"message":"[Response Ops][Actions] Adding configuration to override default MS Graph API Scope and Exchange URL values (#175812)\n\nResolves https://github.com/elastic/kibana/issues/166064\r\n\r\n## Summary\r\n\r\nAdds the following configurations to the `kibana.yml` config:\r\n* `xpack.actions.microsoftGraphApiScope` - overrides the default Graph\r\nAPI scope value of `https://graph.microsoft.com/.default`\r\n* `xpack.actions.microsoftExchangeUrl` - overrides the default value of\r\n`https://login.microsoftonline.com`\r\n\r\nThis allows users in different Azure environments to customize their\r\nendpoints as needed.\r\n\r\n## To Verify\r\n\r\nWe are unable to test this in a different environment but we can verify\r\nthat the config overrides the defaults as expected by setting the config\r\nvalues to something different and the logging out the params that are\r\nsent to `getOAuthClientCredentialsAccessToken` in\r\n`x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts`.\r\nThen create an MS Exchange email connector and test it to see that the\r\nlogged values are overridden as expected.\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>","sha":"f7e4f7a636763d46cb6a38b21a5eb6e67595ddfe"}}]}] BACKPORT--> Co-authored-by: Ying Mao <ying.mao@elastic.co>
This commit is contained in:
parent
9945cffe4a
commit
3f4a7a561b
16 changed files with 205 additions and 23 deletions
|
@ -142,6 +142,15 @@ A list of action types that are enabled. It defaults to `["*"]`, enabling all ty
|
|||
+
|
||||
Disabled action types will not appear as an option when creating new connectors, but existing connectors and actions of that type will remain in {kib} and will not function.
|
||||
|
||||
`xpack.actions.microsoftExchangeUrl`::
|
||||
The URL for the Microsoft Azure Active Directory endpoint to use for MS Exchange email authentication. Default: `https://login.microsoftonline.com`.
|
||||
|
||||
`xpack.actions.microsoftGraphApiUrl`::
|
||||
The URL for the Microsoft Graph API endpoint to use for MS Exchange email authentication. Default: `https://graph.microsoft.com/v1.0`.
|
||||
|
||||
`xpack.actions.microsoftGraphApiScope`::
|
||||
The URL for the Microsoft Graph API scope endpoint to use for MS Exchange email authentication. Default: `https://graph.microsoft.com/.default`.
|
||||
|
||||
`xpack.actions.proxyUrl` {ess-icon}::
|
||||
Specifies the proxy URL to use, if using a proxy for actions. By default, no proxy is used.
|
||||
+
|
||||
|
|
|
@ -19,3 +19,7 @@ export * from './execution_log_types';
|
|||
export const BASE_ACTION_API_PATH = '/api/actions';
|
||||
export const INTERNAL_BASE_ACTION_API_PATH = '/internal/actions';
|
||||
export const ACTIONS_FEATURE_ID = 'actions';
|
||||
|
||||
export const DEFAULT_MICROSOFT_EXCHANGE_URL = 'https://login.microsoftonline.com';
|
||||
export const DEFAULT_MICROSOFT_GRAPH_API_URL = 'https://graph.microsoft.com/v1.0';
|
||||
export const DEFAULT_MICROSOFT_GRAPH_API_SCOPE = 'https://graph.microsoft.com/.default';
|
||||
|
|
|
@ -8,7 +8,11 @@
|
|||
import { schema } from '@kbn/config-schema';
|
||||
import moment from 'moment';
|
||||
import { ByteSizeValue } from '@kbn/config-schema';
|
||||
|
||||
import {
|
||||
DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
} from '../../common';
|
||||
import { ActionTypeRegistry, ActionTypeRegistryOpts } from '../action_type_registry';
|
||||
import { ActionsClient } from './actions_client';
|
||||
import { ExecutorType, ActionType } from '../types';
|
||||
|
@ -596,6 +600,9 @@ describe('create()', () => {
|
|||
proxyVerificationMode: 'full',
|
||||
},
|
||||
enableFooterInEmail: true,
|
||||
microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
});
|
||||
|
||||
const localActionTypeRegistryParams = {
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
} from '../common';
|
||||
import { ActionsConfigurationUtilities } from './actions_config';
|
||||
|
||||
const createActionsConfigMock = () => {
|
||||
|
@ -24,7 +29,9 @@ const createActionsConfigMock = () => {
|
|||
timeout: 360000,
|
||||
}),
|
||||
getCustomHostSettings: jest.fn().mockReturnValue(undefined),
|
||||
getMicrosoftGraphApiUrl: jest.fn().mockReturnValue(undefined),
|
||||
getMicrosoftGraphApiUrl: jest.fn().mockReturnValue(DEFAULT_MICROSOFT_GRAPH_API_URL),
|
||||
getMicrosoftGraphApiScope: jest.fn().mockReturnValue(DEFAULT_MICROSOFT_GRAPH_API_SCOPE),
|
||||
getMicrosoftExchangeUrl: jest.fn().mockReturnValue(DEFAULT_MICROSOFT_EXCHANGE_URL),
|
||||
validateEmailAddresses: jest.fn().mockReturnValue(undefined),
|
||||
getMaxAttempts: jest.fn().mockReturnValue(3),
|
||||
enableFooterInEmail: jest.fn().mockReturnValue(true),
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
|
||||
import { ByteSizeValue } from '@kbn/config-schema';
|
||||
import { ActionsConfig } from './config';
|
||||
import {
|
||||
DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
} from '../common';
|
||||
import {
|
||||
getActionsConfigurationUtilities,
|
||||
AllowedHosts,
|
||||
|
@ -34,6 +39,9 @@ const defaultActionsConfig: ActionsConfig = {
|
|||
verificationMode: 'full',
|
||||
},
|
||||
enableFooterInEmail: true,
|
||||
microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
};
|
||||
|
||||
describe('ensureUriAllowed', () => {
|
||||
|
|
|
@ -47,7 +47,9 @@ export interface ActionsConfigurationUtilities {
|
|||
getProxySettings: () => undefined | ProxySettings;
|
||||
getResponseSettings: () => ResponseSettings;
|
||||
getCustomHostSettings: (targetUrl: string) => CustomHostSettings | undefined;
|
||||
getMicrosoftGraphApiUrl: () => undefined | string;
|
||||
getMicrosoftGraphApiUrl: () => string;
|
||||
getMicrosoftGraphApiScope: () => string;
|
||||
getMicrosoftExchangeUrl: () => string;
|
||||
getMaxAttempts: ({
|
||||
actionTypeMaxAttempts,
|
||||
actionTypeId,
|
||||
|
@ -127,10 +129,18 @@ function getProxySettingsFromConfig(config: ActionsConfig): undefined | ProxySet
|
|||
};
|
||||
}
|
||||
|
||||
function getMicrosoftGraphApiUrlFromConfig(config: ActionsConfig): undefined | string {
|
||||
function getMicrosoftGraphApiUrlFromConfig(config: ActionsConfig): string {
|
||||
return config.microsoftGraphApiUrl;
|
||||
}
|
||||
|
||||
function getMicrosoftGraphApiScopeFromConfig(config: ActionsConfig): string {
|
||||
return config.microsoftGraphApiScope;
|
||||
}
|
||||
|
||||
function getMicrosoftExchangeUrlFromConfig(config: ActionsConfig): string {
|
||||
return config.microsoftExchangeUrl;
|
||||
}
|
||||
|
||||
function arrayAsSet<T>(arr: T[] | undefined): Set<T> | undefined {
|
||||
if (!arr) return;
|
||||
return new Set(arr);
|
||||
|
@ -209,6 +219,8 @@ export function getActionsConfigurationUtilities(
|
|||
},
|
||||
getCustomHostSettings: (targetUrl: string) => getCustomHostSettings(config, targetUrl),
|
||||
getMicrosoftGraphApiUrl: () => getMicrosoftGraphApiUrlFromConfig(config),
|
||||
getMicrosoftGraphApiScope: () => getMicrosoftGraphApiScopeFromConfig(config),
|
||||
getMicrosoftExchangeUrl: () => getMicrosoftExchangeUrlFromConfig(config),
|
||||
validateEmailAddresses: (addresses: string[], options: ValidateEmailAddressesOptions) =>
|
||||
validatedEmailCurried(addresses, options),
|
||||
getMaxAttempts: ({ actionTypeMaxAttempts, actionTypeId }) => {
|
||||
|
|
|
@ -30,6 +30,9 @@ describe('config validation', () => {
|
|||
"maxResponseContentLength": ByteSizeValue {
|
||||
"valueInBytes": 1048576,
|
||||
},
|
||||
"microsoftExchangeUrl": "https://login.microsoftonline.com",
|
||||
"microsoftGraphApiScope": "https://graph.microsoft.com/.default",
|
||||
"microsoftGraphApiUrl": "https://graph.microsoft.com/v1.0",
|
||||
"preconfigured": Object {},
|
||||
"preconfiguredAlertHistoryEsIndex": false,
|
||||
"proxyRejectUnauthorizedCertificates": true,
|
||||
|
@ -65,6 +68,9 @@ describe('config validation', () => {
|
|||
"maxResponseContentLength": ByteSizeValue {
|
||||
"valueInBytes": 1048576,
|
||||
},
|
||||
"microsoftExchangeUrl": "https://login.microsoftonline.com",
|
||||
"microsoftGraphApiScope": "https://graph.microsoft.com/.default",
|
||||
"microsoftGraphApiUrl": "https://graph.microsoft.com/v1.0",
|
||||
"preconfigured": Object {
|
||||
"mySlack1": Object {
|
||||
"actionTypeId": ".slack",
|
||||
|
@ -147,7 +153,7 @@ describe('config validation', () => {
|
|||
expect(mockLogger.warn.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"The confgurations xpack.actions.proxyBypassHosts and xpack.actions.proxyOnlyHosts can not be used at the same time. The configuration xpack.actions.proxyOnlyHosts will be ignored.",
|
||||
"The configurations xpack.actions.proxyBypassHosts and xpack.actions.proxyOnlyHosts can not be used at the same time. The configuration xpack.actions.proxyOnlyHosts will be ignored.",
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -169,7 +175,7 @@ describe('config validation', () => {
|
|||
expect(mockLogger.warn.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"The confguration xpack.actions.proxyUrl: bad url is invalid.",
|
||||
"The configuration xpack.actions.proxyUrl: bad url is invalid.",
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -207,6 +213,9 @@ describe('config validation', () => {
|
|||
"maxResponseContentLength": ByteSizeValue {
|
||||
"valueInBytes": 1048576,
|
||||
},
|
||||
"microsoftExchangeUrl": "https://login.microsoftonline.com",
|
||||
"microsoftGraphApiScope": "https://graph.microsoft.com/.default",
|
||||
"microsoftGraphApiUrl": "https://graph.microsoft.com/v1.0",
|
||||
"preconfigured": Object {},
|
||||
"preconfiguredAlertHistoryEsIndex": false,
|
||||
"proxyRejectUnauthorizedCertificates": true,
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
|
||||
import { schema, TypeOf } from '@kbn/config-schema';
|
||||
import { Logger } from '@kbn/core/server';
|
||||
import {
|
||||
DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
} from '../common';
|
||||
|
||||
export enum AllowedHosts {
|
||||
Any = '*',
|
||||
|
@ -120,7 +125,9 @@ export const configSchema = schema.object({
|
|||
maxResponseContentLength: schema.byteSize({ defaultValue: '1mb' }),
|
||||
responseTimeout: schema.duration({ defaultValue: '60s' }),
|
||||
customHostSettings: schema.maybe(schema.arrayOf(customHostSettingsSchema)),
|
||||
microsoftGraphApiUrl: schema.maybe(schema.string()),
|
||||
microsoftGraphApiUrl: schema.string({ defaultValue: DEFAULT_MICROSOFT_GRAPH_API_URL }),
|
||||
microsoftGraphApiScope: schema.string({ defaultValue: DEFAULT_MICROSOFT_GRAPH_API_SCOPE }),
|
||||
microsoftExchangeUrl: schema.string({ defaultValue: DEFAULT_MICROSOFT_EXCHANGE_URL }),
|
||||
email: schema.maybe(
|
||||
schema.object({
|
||||
domain_allowlist: schema.arrayOf(schema.string()),
|
||||
|
@ -155,13 +162,13 @@ export function getValidatedConfig(logger: Logger, originalConfig: ActionsConfig
|
|||
try {
|
||||
new URL(proxyUrl);
|
||||
} catch (err) {
|
||||
logger.warn(`The confguration xpack.actions.proxyUrl: ${proxyUrl} is invalid.`);
|
||||
logger.warn(`The configuration xpack.actions.proxyUrl: ${proxyUrl} is invalid.`);
|
||||
}
|
||||
}
|
||||
|
||||
if (proxyBypassHosts && proxyOnlyHosts) {
|
||||
logger.warn(
|
||||
'The confgurations xpack.actions.proxyBypassHosts and xpack.actions.proxyOnlyHosts can not be used at the same time. The configuration xpack.actions.proxyOnlyHosts will be ignored.'
|
||||
'The configurations xpack.actions.proxyBypassHosts and xpack.actions.proxyOnlyHosts can not be used at the same time. The configuration xpack.actions.proxyOnlyHosts will be ignored.'
|
||||
);
|
||||
const tmp: Record<string, unknown> = originalConfig;
|
||||
delete tmp.proxyOnlyHosts;
|
||||
|
|
|
@ -23,6 +23,11 @@ import { createReadySignal } from '@kbn/event-log-plugin/server/lib/ready_signal
|
|||
import { ActionsConfig } from '../config';
|
||||
import { ActionsConfigurationUtilities, getActionsConfigurationUtilities } from '../actions_config';
|
||||
import { resolveCustomHosts } from '../lib/custom_host_settings';
|
||||
import {
|
||||
DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
} from '../../common';
|
||||
|
||||
const logger = loggingSystemMock.create().get() as jest.Mocked<Logger>;
|
||||
|
||||
|
@ -683,6 +688,9 @@ const BaseActionsConfig: ActionsConfig = {
|
|||
responseTimeout: momentDuration(1000 * 30),
|
||||
customHostSettings: undefined,
|
||||
enableFooterInEmail: true,
|
||||
microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
};
|
||||
|
||||
function getACUfromConfig(config: Partial<ActionsConfig> = {}): ActionsConfigurationUtilities {
|
||||
|
|
|
@ -23,6 +23,11 @@ import { createReadySignal } from '@kbn/event-log-plugin/server/lib/ready_signal
|
|||
import { ActionsConfig } from '../config';
|
||||
import { ActionsConfigurationUtilities, getActionsConfigurationUtilities } from '../actions_config';
|
||||
import { resolveCustomHosts } from '../lib/custom_host_settings';
|
||||
import {
|
||||
DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
} from '../../common';
|
||||
|
||||
const logger = loggingSystemMock.create().get() as jest.Mocked<Logger>;
|
||||
|
||||
|
@ -589,6 +594,9 @@ const BaseActionsConfig: ActionsConfig = {
|
|||
responseTimeout: momentDuration(1000 * 30),
|
||||
customHostSettings: undefined,
|
||||
enableFooterInEmail: true,
|
||||
microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
};
|
||||
|
||||
function getACUfromConfig(config: Partial<ActionsConfig> = {}): ActionsConfigurationUtilities {
|
||||
|
|
|
@ -15,6 +15,11 @@ import { Logger } from '@kbn/core/server';
|
|||
import { loggingSystemMock } from '@kbn/core/server/mocks';
|
||||
|
||||
import { resolveCustomHosts, getCanonicalCustomHostUrl } from './custom_host_settings';
|
||||
import {
|
||||
DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
} from '../../common';
|
||||
|
||||
const CA_DIR = '../../../../../../packages/kbn-dev-utils/certs';
|
||||
const CA_FILE1 = pathResolve(__filename, pathJoin(CA_DIR, 'ca.crt'));
|
||||
|
@ -74,6 +79,9 @@ describe('custom_host_settings', () => {
|
|||
maxResponseContentLength: new ByteSizeValue(1000000),
|
||||
responseTimeout: moment.duration(60000),
|
||||
enableFooterInEmail: true,
|
||||
microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
};
|
||||
|
||||
test('ensure it copies over the config parts that it does not touch', () => {
|
||||
|
|
|
@ -24,7 +24,12 @@ import {
|
|||
ActionsPluginsStart,
|
||||
PluginSetupContract,
|
||||
} from './plugin';
|
||||
import { AlertHistoryEsIndexConnectorId } from '../common';
|
||||
import {
|
||||
AlertHistoryEsIndexConnectorId,
|
||||
DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
} from '../common';
|
||||
|
||||
const executor: ExecutorType<{}, {}, {}, void> = async (options) => {
|
||||
return { status: 'ok', actionId: options.actionId };
|
||||
|
@ -51,6 +56,9 @@ function getConfig(overrides = {}) {
|
|||
maxResponseContentLength: new ByteSizeValue(1000000),
|
||||
responseTimeout: moment.duration('60s'),
|
||||
enableFooterInEmail: true,
|
||||
microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
@ -73,6 +81,9 @@ describe('Actions Plugin', () => {
|
|||
maxResponseContentLength: new ByteSizeValue(1000000),
|
||||
responseTimeout: moment.duration(60000),
|
||||
enableFooterInEmail: true,
|
||||
microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
});
|
||||
plugin = new ActionsPlugin(context);
|
||||
coreSetup = coreMock.createSetup();
|
||||
|
@ -534,6 +545,9 @@ describe('Actions Plugin', () => {
|
|||
maxResponseContentLength: new ByteSizeValue(1000000),
|
||||
responseTimeout: moment.duration(60000),
|
||||
enableFooterInEmail: true,
|
||||
microsoftGraphApiUrl: DEFAULT_MICROSOFT_GRAPH_API_URL,
|
||||
microsoftGraphApiScope: DEFAULT_MICROSOFT_GRAPH_API_SCOPE,
|
||||
microsoftExchangeUrl: DEFAULT_MICROSOFT_EXCHANGE_URL,
|
||||
});
|
||||
plugin = new ActionsPlugin(context);
|
||||
coreSetup = coreMock.createSetup();
|
||||
|
|
|
@ -179,7 +179,6 @@ describe('send_email module', () => {
|
|||
expect(sendEmailGraphApiMock.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"graphApiUrl": undefined,
|
||||
"headers": Object {
|
||||
"Authorization": "Bearer dfjsdfgdjhfgsjdf",
|
||||
"Content-Type": "application/json",
|
||||
|
@ -232,6 +231,82 @@ describe('send_email module', () => {
|
|||
`);
|
||||
});
|
||||
|
||||
test('uses custom graph API scope if configured for OAuth 2.0 Client Credentials authentication for email using "exchange_server" service', async () => {
|
||||
const sendEmailGraphApiMock = sendEmailGraphApi as jest.Mock;
|
||||
const getOAuthClientCredentialsAccessTokenMock =
|
||||
getOAuthClientCredentialsAccessToken as jest.Mock;
|
||||
const sendEmailOptions = getSendEmailOptions({
|
||||
transport: {
|
||||
service: 'exchange_server',
|
||||
clientId: '123456',
|
||||
tenantId: '98765',
|
||||
clientSecret: 'sdfhkdsjhfksdjfh',
|
||||
},
|
||||
});
|
||||
sendEmailOptions.configurationUtilities.getMicrosoftGraphApiScope.mockReturnValueOnce(
|
||||
'https://dod-graph.microsoft.us/.default'
|
||||
);
|
||||
getOAuthClientCredentialsAccessTokenMock.mockReturnValueOnce(`Bearer dfjsdfgdjhfgsjdf`);
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() + 5);
|
||||
|
||||
sendEmailGraphApiMock.mockReturnValue({
|
||||
status: 202,
|
||||
});
|
||||
|
||||
await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient);
|
||||
expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({
|
||||
configurationUtilities: sendEmailOptions.configurationUtilities,
|
||||
connectorId: '1',
|
||||
connectorTokenClient,
|
||||
credentials: {
|
||||
config: { clientId: '123456', tenantId: '98765' },
|
||||
secrets: { clientSecret: 'sdfhkdsjhfksdjfh' },
|
||||
},
|
||||
logger: mockLogger,
|
||||
oAuthScope: 'https://dod-graph.microsoft.us/.default',
|
||||
tokenUrl: 'https://login.microsoftonline.com/98765/oauth2/v2.0/token',
|
||||
});
|
||||
});
|
||||
|
||||
test('uses custom exchange URL if configured for OAuth 2.0 Client Credentials authentication for email using "exchange_server" service', async () => {
|
||||
const sendEmailGraphApiMock = sendEmailGraphApi as jest.Mock;
|
||||
const getOAuthClientCredentialsAccessTokenMock =
|
||||
getOAuthClientCredentialsAccessToken as jest.Mock;
|
||||
const sendEmailOptions = getSendEmailOptions({
|
||||
transport: {
|
||||
service: 'exchange_server',
|
||||
clientId: '123456',
|
||||
tenantId: '98765',
|
||||
clientSecret: 'sdfhkdsjhfksdjfh',
|
||||
},
|
||||
});
|
||||
sendEmailOptions.configurationUtilities.getMicrosoftExchangeUrl.mockReturnValueOnce(
|
||||
'https://login.microsoftonline.us'
|
||||
);
|
||||
getOAuthClientCredentialsAccessTokenMock.mockReturnValueOnce(`Bearer dfjsdfgdjhfgsjdf`);
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() + 5);
|
||||
|
||||
sendEmailGraphApiMock.mockReturnValue({
|
||||
status: 202,
|
||||
});
|
||||
|
||||
await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient);
|
||||
expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({
|
||||
configurationUtilities: sendEmailOptions.configurationUtilities,
|
||||
connectorId: '1',
|
||||
connectorTokenClient,
|
||||
credentials: {
|
||||
config: { clientId: '123456', tenantId: '98765' },
|
||||
secrets: { clientSecret: 'sdfhkdsjhfksdjfh' },
|
||||
},
|
||||
logger: mockLogger,
|
||||
oAuthScope: 'https://graph.microsoft.com/.default',
|
||||
tokenUrl: 'https://login.microsoftonline.us/98765/oauth2/v2.0/token',
|
||||
});
|
||||
});
|
||||
|
||||
test('throws error if null access token returned when using OAuth 2.0 Client Credentials authentication', async () => {
|
||||
const sendEmailGraphApiMock = sendEmailGraphApi as jest.Mock;
|
||||
const getOAuthClientCredentialsAccessTokenMock =
|
||||
|
|
|
@ -25,8 +25,6 @@ import { sendEmailGraphApi } from './send_email_graph_api';
|
|||
// an email "service" which doesn't actually send, just returns what it would send
|
||||
export const JSON_TRANSPORT_SERVICE = '__json';
|
||||
// The value is the resource identifier (Application ID URI) of the resource you want, affixed with the .default suffix. For Microsoft Graph, the value is https://graph.microsoft.com/.default. This value informs the Microsoft identity platform endpoint that of all the application permissions you have configured for your app in the app registration portal, it should issue a token for the ones associated with the resource you want to use.
|
||||
export const GRAPH_API_OAUTH_SCOPE = 'https://graph.microsoft.com/.default';
|
||||
export const EXCHANGE_ONLINE_SERVER_HOST = 'https://login.microsoftonline.com';
|
||||
|
||||
export interface SendEmailOptions {
|
||||
connectorId: string;
|
||||
|
@ -92,6 +90,12 @@ export async function sendEmailWithExchange(
|
|||
const { transport, configurationUtilities, connectorId } = options;
|
||||
const { clientId, clientSecret, tenantId, oauthTokenUrl } = transport;
|
||||
|
||||
let tokenUrl = oauthTokenUrl;
|
||||
if (!tokenUrl) {
|
||||
const exchangeUrl = configurationUtilities.getMicrosoftExchangeUrl();
|
||||
tokenUrl = `${exchangeUrl}/${tenantId}/oauth2/v2.0/token`;
|
||||
}
|
||||
|
||||
const accessToken = await getOAuthClientCredentialsAccessToken({
|
||||
connectorId,
|
||||
logger,
|
||||
|
@ -105,8 +109,8 @@ export async function sendEmailWithExchange(
|
|||
clientSecret: clientSecret as string,
|
||||
},
|
||||
},
|
||||
oAuthScope: GRAPH_API_OAUTH_SCOPE,
|
||||
tokenUrl: oauthTokenUrl ?? `${EXCHANGE_ONLINE_SERVER_HOST}/${tenantId}/oauth2/v2.0/token`,
|
||||
oAuthScope: configurationUtilities.getMicrosoftGraphApiScope(),
|
||||
tokenUrl,
|
||||
connectorTokenClient,
|
||||
});
|
||||
|
||||
|
@ -148,7 +152,6 @@ export async function sendEmailWithExchange(
|
|||
options,
|
||||
headers,
|
||||
messageHTML,
|
||||
graphApiUrl: configurationUtilities.getMicrosoftGraphApiUrl(),
|
||||
},
|
||||
logger,
|
||||
configurationUtilities,
|
||||
|
|
|
@ -32,7 +32,11 @@ describe('sendEmailGraphApi', () => {
|
|||
status: 202,
|
||||
});
|
||||
await sendEmailGraphApi(
|
||||
{ options: getSendEmailOptions(), messageHTML: 'test1', headers: {} },
|
||||
{
|
||||
options: getSendEmailOptions(),
|
||||
messageHTML: 'test1',
|
||||
headers: {},
|
||||
},
|
||||
logger,
|
||||
configurationUtilities
|
||||
);
|
||||
|
@ -207,12 +211,12 @@ describe('sendEmailGraphApi', () => {
|
|||
axiosInstanceMock.mockReturnValueOnce({
|
||||
status: 202,
|
||||
});
|
||||
configurationUtilities.getMicrosoftGraphApiUrl.mockReturnValueOnce('https://test');
|
||||
await sendEmailGraphApi(
|
||||
{
|
||||
options: getSendEmailOptions(),
|
||||
messageHTML: 'test3',
|
||||
headers: {},
|
||||
graphApiUrl: 'https://test',
|
||||
},
|
||||
logger,
|
||||
configurationUtilities
|
||||
|
|
|
@ -17,18 +17,15 @@ interface SendEmailGraphApiOptions {
|
|||
options: SendEmailOptions;
|
||||
headers: Record<string, string>;
|
||||
messageHTML: string;
|
||||
graphApiUrl?: string;
|
||||
}
|
||||
|
||||
const MICROSOFT_GRAPH_API_HOST = 'https://graph.microsoft.com/v1.0';
|
||||
|
||||
export async function sendEmailGraphApi(
|
||||
sendEmailOptions: SendEmailGraphApiOptions,
|
||||
logger: Logger,
|
||||
configurationUtilities: ActionsConfigurationUtilities,
|
||||
axiosInstance?: AxiosInstance
|
||||
): Promise<AxiosResponse> {
|
||||
const { options, headers, messageHTML, graphApiUrl } = sendEmailOptions;
|
||||
const { options, headers, messageHTML } = sendEmailOptions;
|
||||
|
||||
// Create a new axios instance if one is not provided
|
||||
axiosInstance = axiosInstance ?? axios.create();
|
||||
|
@ -36,7 +33,9 @@ export async function sendEmailGraphApi(
|
|||
// POST /users/{id | userPrincipalName}/sendMail
|
||||
const res = await request({
|
||||
axios: axiosInstance,
|
||||
url: `${graphApiUrl ?? MICROSOFT_GRAPH_API_HOST}/users/${options.routing.from}/sendMail`,
|
||||
url: `${configurationUtilities.getMicrosoftGraphApiUrl()}/users/${
|
||||
options.routing.from
|
||||
}/sendMail`,
|
||||
method: 'post',
|
||||
logger,
|
||||
data: getMessage(options, messageHTML),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue