diff --git a/Common/sources/utils.js b/Common/sources/utils.js index 8a21e160..a4a067fd 100644 --- a/Common/sources/utils.js +++ b/Common/sources/utils.js @@ -463,7 +463,7 @@ function downloadUrlPromiseWithoutRedirect(ctx, uri, optTimeout, optLimit, opt_A } }); } -function postRequestPromise(ctx, uri, postData, postDataStream, postDataSize, optTimeout, opt_Authorization, opt_headers) { +function postRequestPromise(ctx, uri, postData, postDataStream, postDataSize, optTimeout, opt_Authorization, opt_isInJwtToken, opt_headers) { return new Promise(function(resolve, reject) { const tenTenantRequestDefaults = ctx.getCfg('services.CoAuthoring.requestDefaults', cfgRequestDefaults); const tenTokenOutboxHeader = ctx.getCfg('services.CoAuthoring.token.outbox.header', cfgTokenOutboxHeader); @@ -474,8 +474,14 @@ function postRequestPromise(ctx, uri, postData, postDataStream, postDataSize, op let connectionAndInactivity = optTimeout && optTimeout.connectionAndInactivity && ms(optTimeout.connectionAndInactivity); let options = config.util.extendDeep({}, tenTenantRequestDefaults); Object.assign(options, {uri: urlParsed, encoding: 'utf8', timeout: connectionAndInactivity}); - //baseRequest creates new agent(win-ca injects in globalAgent) - options.agentOptions = https.globalAgent.options; + if (!addExternalRequestOptions(ctx, uri, opt_isInJwtToken, options)) { + reject(new Error('Block external request. See externalRequest config options')); + return; + } + if (!options.agent) { + //baseRequest creates new agent(win-ca injects in globalAgent) + options.agentOptions = https.globalAgent.options; + } if (postData) { options.body = postData; } diff --git a/DocService/sources/DocsCoServer.js b/DocService/sources/DocsCoServer.js index e1ad2203..0891e0c3 100644 --- a/DocService/sources/DocsCoServer.js +++ b/DocService/sources/DocsCoServer.js @@ -736,6 +736,7 @@ async function getOriginalParticipantsId(ctx, docId) { async function sendServerRequest(ctx, uri, dataObject, opt_checkAndFixAuthorizationLength) { const tenCallbackRequestTimeout = ctx.getCfg('services.CoAuthoring.server.callbackRequestTimeout', cfgCallbackRequestTimeout); + const tenTokenEnableRequestInbox = ctx.getCfg('services.CoAuthoring.token.enable.request.inbox', cfgTokenEnableRequestInbox); ctx.logger.debug('postData request: url = %s;data = %j', uri, dataObject); let auth; @@ -751,7 +752,8 @@ async function sendServerRequest(ctx, uri, dataObject, opt_checkAndFixAuthorizat dataObject.setToken(bodyToken); } let headers = {'Content-Type': 'application/json'}; - let postRes = await utils.postRequestPromise(ctx, uri, JSON.stringify(dataObject), undefined, undefined, tenCallbackRequestTimeout, auth, headers); + //isInJwtToken is true because callbackUrl is required field in jwt token + let postRes = await utils.postRequestPromise(ctx, uri, JSON.stringify(dataObject), undefined, undefined, tenCallbackRequestTimeout, auth, tenTokenEnableRequestInbox, headers); ctx.logger.debug('postData response: data = %s', postRes.body); return postRes.body; } @@ -1634,7 +1636,7 @@ exports.install = function(server, callbackFunction) { return; } if (getIsShutdown()) { - sendFileError(ctx, conn, 'Server shutdow'); + sendFileError(ctx, conn, 'Server shutdown'); return; } conn.baseUrl = utils.getBaseUrlByConnection(ctx, conn); @@ -4251,6 +4253,7 @@ function* commandLicense(ctx) { async function proxyCommand(ctx, req, params) { const tenCallbackRequestTimeout = ctx.getCfg('services.CoAuthoring.server.callbackRequestTimeout', cfgCallbackRequestTimeout); + const tenTokenEnableRequestInbox = ctx.getCfg('services.CoAuthoring.token.enable.request.inbox', cfgTokenEnableRequestInbox); //todo gen shardkey as in sdkjs const shardkey = params.key; const baseUrl = utils.getBaseUrlByRequest(ctx, req); @@ -4259,7 +4262,8 @@ async function proxyCommand(ctx, req, params) { url += `&${name}=${encodeURIComponent(req.query[name])}`; } ctx.logger.info('commandFromServer proxy request with "key" to correctly process commands in sharded cluster to url:%s', url); - return await utils.postRequestPromise(ctx, url, req.body, null, req.body.length, tenCallbackRequestTimeout, undefined, req.headers); + //isInJwtToken is true because 'command' is always internal + return await utils.postRequestPromise(ctx, url, req.body, null, req.body.length, tenCallbackRequestTimeout, undefined, tenTokenEnableRequestInbox, req.headers); } /** * Server commands handler. diff --git a/DocService/sources/wopiClient.js b/DocService/sources/wopiClient.js index 02903d0d..120556d5 100644 --- a/DocService/sources/wopiClient.js +++ b/DocService/sources/wopiClient.js @@ -719,7 +719,9 @@ function putFile(ctx, wopiParams, data, dataStream, dataSize, userLastChangeId, headers['Content-Type'] = mime.getType(getFileTypeByInfo(fileInfo)); ctx.logger.debug('wopi PutFile request uri=%s headers=%j', uri, headers); - postRes = yield utils.postRequestPromise(ctx, uri, data, dataStream, dataSize, tenCallbackRequestTimeout, undefined, headers); + //isInJwtToken is true because it passed checkIpFilter for wopi + let isInJwtToken = true; + postRes = yield utils.postRequestPromise(ctx, uri, data, dataStream, dataSize, tenCallbackRequestTimeout, undefined, isInJwtToken, headers); ctx.logger.debug('wopi PutFile response headers=%j', postRes.response.headers); ctx.logger.debug('wopi PutFile response body:%s', postRes.body); } else { @@ -754,7 +756,9 @@ function putRelativeFile(ctx, wopiSrc, access_token, data, dataStream, dataSize, headers['Content-Type'] = mime.getType(suggestedExt); ctx.logger.debug('wopi putRelativeFile request uri=%s headers=%j', uri, headers); - let postRes = yield utils.postRequestPromise(ctx, uri, data, dataStream, dataSize, tenCallbackRequestTimeout, undefined, headers); + //isInJwtToken is true because it passed checkIpFilter for wopi + let isInJwtToken = true; + let postRes = yield utils.postRequestPromise(ctx, uri, data, dataStream, dataSize, tenCallbackRequestTimeout, undefined, isInJwtToken, headers); ctx.logger.debug('wopi putRelativeFile response headers=%j', postRes.response.headers); ctx.logger.debug('wopi putRelativeFile response body:%s', postRes.body); res = JSON.parse(postRes.body); @@ -793,7 +797,9 @@ function renameFile(ctx, wopiParams, name) { yield fillStandardHeaders(ctx, headers, uri, userAuth.access_token); ctx.logger.debug('wopi RenameFile request uri=%s headers=%j', uri, headers); - let postRes = yield utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, headers); + //isInJwtToken is true because it passed checkIpFilter for wopi + let isInJwtToken = true; + let postRes = yield utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, isInJwtToken, headers); ctx.logger.debug('wopi RenameFile response headers=%j body=%s', postRes.response.headers, postRes.body); if (postRes.body) { res = JSON.parse(postRes.body); @@ -830,8 +836,7 @@ function checkFileInfo(ctx, wopiSrc, access_token, opt_sc) { } yield fillStandardHeaders(ctx, headers, uri, access_token); ctx.logger.debug('wopi checkFileInfo request uri=%s headers=%j', uri, headers); - //todo false? (true because it passed checkIpFilter for wopi) - //todo use directIfIn + //isInJwtToken is true because it passed checkIpFilter for wopi let isInJwtToken = true; let getRes = yield utils.downloadUrlPromise(ctx, uri, tenDownloadTimeout, undefined, undefined, isInJwtToken, headers); ctx.logger.debug(`wopi checkFileInfo headers=%j body=%s`, getRes.response.headers, getRes.body); @@ -866,7 +871,9 @@ function lock(ctx, command, lockId, fileInfo, userAuth) { let headers = {"X-WOPI-Override": command, "X-WOPI-Lock": lockId}; yield fillStandardHeaders(ctx, headers, uri, access_token); ctx.logger.debug('wopi %s request uri=%s headers=%j', command, uri, headers); - let postRes = yield utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, headers); + //isInJwtToken is true because it passed checkIpFilter for wopi + let isInJwtToken = true; + let postRes = yield utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, isInJwtToken, headers); ctx.logger.debug('wopi %s response headers=%j', command, postRes.response.headers); } else { ctx.logger.info('wopi %s SupportsLocks = false', command); @@ -903,7 +910,9 @@ async function unlock(ctx, wopiParams) { let headers = {"X-WOPI-Override": "UNLOCK", "X-WOPI-Lock": lockId}; await fillStandardHeaders(ctx, headers, uri, access_token); ctx.logger.debug('wopi Unlock request uri=%s headers=%j', uri, headers); - let postRes = await utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, headers); + //isInJwtToken is true because it passed checkIpFilter for wopi + let isInJwtToken = true; + let postRes = await utils.postRequestPromise(ctx, uri, undefined, undefined, undefined, tenCallbackRequestTimeout, undefined, isInJwtToken, headers); ctx.logger.debug('wopi Unlock response headers=%j', postRes.response.headers); } else { ctx.logger.info('wopi SupportsLocks = false');