[Response Ops][Actions] Adding configuration to override default MS Graph API Scope and Exchange URL values (#175812)

Resolves https://github.com/elastic/kibana/issues/166064

## Summary

Adds the following configurations to the `kibana.yml` config:
* `xpack.actions.microsoftGraphApiScope` - overrides the default Graph
API scope value of `https://graph.microsoft.com/.default`
* `xpack.actions.microsoftExchangeUrl` - overrides the default value of
`https://login.microsoftonline.com`

This allows users in different Azure environments to customize their
endpoints as needed.

## To Verify

We are unable to test this in a different environment but we can verify
that the config overrides the defaults as expected by setting the config
values to something different and the logging out the params that are
sent to `getOAuthClientCredentialsAccessToken` in
`x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts`.
Then create an MS Exchange email connector and test it to see that the
logged values are overridden as expected.

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Ying Mao 2024-02-01 12:41:52 -05:00 committed by GitHub
parent 859e440eb9
commit f7e4f7a636
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 205 additions and 23 deletions

View file

@ -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.
+

View file

@ -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';

View file

@ -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 = {

View file

@ -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),

View file

@ -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', () => {

View file

@ -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 }) => {

View file

@ -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,

View file

@ -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;

View file

@ -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 {

View file

@ -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 {

View file

@ -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', () => {

View file

@ -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();

View file

@ -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 =

View file

@ -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,

View file

@ -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

View file

@ -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),