From de6713f76631c4061e58f56fd3c7203f20d793b7 Mon Sep 17 00:00:00 2001 From: Sergey Konovalov Date: Thu, 1 Feb 2018 14:18:45 +0300 Subject: [PATCH] feat: split inbox secret into browser and request part --- Common/config/default.json | 4 +++ Common/sources/commondefines.js | 7 +++++ Common/sources/utils.js | 9 ++---- DocService/sources/DocsCoServer.js | 35 +++++++++++++++-------- DocService/sources/canvasservice.js | 2 +- DocService/sources/fileuploaderservice.js | 2 +- 6 files changed, 39 insertions(+), 20 deletions(-) diff --git a/Common/config/default.json b/Common/config/default.json index 2cfe325b..be38dcc0 100644 --- a/Common/config/default.json +++ b/Common/config/default.json @@ -132,6 +132,7 @@ "errorcode": 401 }, "secret": { + "browser": {"string": "secret", "file": "", "tenants": {}}, "inbox": {"string": "secret", "file": "", "tenants": {}}, "outbox": {"string": "secret", "file": ""}, "session": {"string": "secret", "file": ""} @@ -144,6 +145,9 @@ "outbox": false } }, + "browser": { + "secretFromInbox": false + }, "inbox": { "header": "Authorization", "prefix": "Bearer " diff --git a/Common/sources/commondefines.js b/Common/sources/commondefines.js index 5c1896fd..689ec966 100644 --- a/Common/sources/commondefines.js +++ b/Common/sources/commondefines.js @@ -888,6 +888,12 @@ const c_oAscUrlTypes = { Session: 0, Temporary: 1 }; +const c_oAscSecretType = { + Browser: 0, + Inbox: 1, + Outbox: 2, + Session: 3 +}; const buildVersion = '4.1.2'; const buildNumber = 37; @@ -909,5 +915,6 @@ exports.c_oAscUserAction = c_oAscUserAction; exports.c_oAscServerCommandErrors = c_oAscServerCommandErrors; exports.c_oAscForceSaveTypes = c_oAscForceSaveTypes; exports.c_oAscUrlTypes = c_oAscUrlTypes; +exports.c_oAscSecretType = c_oAscSecretType; exports.buildVersion = buildVersion; exports.buildNumber = buildNumber; diff --git a/Common/sources/utils.js b/Common/sources/utils.js index 9e51d731..a15369ec 100644 --- a/Common/sources/utils.js +++ b/Common/sources/utils.js @@ -64,7 +64,6 @@ var cfgTokenOutboxHeader = config.get('services.CoAuthoring.token.outbox.header' var cfgTokenOutboxPrefix = config.get('services.CoAuthoring.token.outbox.prefix'); var cfgTokenOutboxAlgorithm = config.get('services.CoAuthoring.token.outbox.algorithm'); var cfgTokenOutboxExpires = config.get('services.CoAuthoring.token.outbox.expires'); -var cfgSignatureSecretInbox = config.get('services.CoAuthoring.secret.inbox'); var cfgSignatureSecretOutbox = config.get('services.CoAuthoring.secret.outbox'); var cfgVisibilityTimeout = config.get('queue.visibilityTimeout'); var cfgQueueRetentionPeriod = config.get('queue.retentionPeriod'); @@ -84,7 +83,6 @@ var g_oIpFilterRules = function() { } return res; }(); -var isEmptySecretTenants = isEmptyObject(cfgSignatureSecretInbox.tenants); const pemfileCache = new NodeCache({stdTTL: ms(cfgExpPemStdTtl) / 1000, checkperiod: ms(cfgExpPemCheckPeriod) / 1000, errorOnMissing: false, useClones: true}); exports.CONVERTION_TIMEOUT = 1.5 * (cfgVisibilityTimeout + cfgQueueRetentionPeriod) * 1000; @@ -700,9 +698,8 @@ function getSecretByElem(secretElem) { return secret; } exports.getSecretByElem = getSecretByElem; -function getSecret(docId, opt_iss, opt_token) { - var secretElem = cfgSignatureSecretInbox; - if (!isEmptySecretTenants) { +function getSecret(docId, secretElem, opt_iss, opt_token) { + if (!isEmptyObject(secretElem.tenants)) { var iss; if (opt_token) { //look for issuer @@ -714,7 +711,7 @@ function getSecret(docId, opt_iss, opt_token) { iss = opt_iss; } if (iss) { - secretElem = cfgSignatureSecretInbox.tenants[iss]; + secretElem = secretElem.tenants[iss]; if (!secretElem) { logger.error('getSecret unknown issuer: docId = %s iss = %s', docId, iss); } diff --git a/DocService/sources/DocsCoServer.js b/DocService/sources/DocsCoServer.js index 8264e357..939850c9 100644 --- a/DocService/sources/DocsCoServer.js +++ b/DocService/sources/DocsCoServer.js @@ -130,6 +130,9 @@ const cfgTokenSessionAlgorithm = config.get('token.session.algorithm'); const cfgTokenSessionExpires = ms(config.get('token.session.expires')); const cfgTokenInboxHeader = config.get('token.inbox.header'); const cfgTokenInboxPrefix = config.get('token.inbox.prefix'); +const cfgTokenBrowserSecretFromInbox = config.get('token.browser.secretFromInbox'); +const cfgSecretBrowser = config.get('secret.browser'); +const cfgSecretInbox = config.get('secret.inbox'); const cfgSecretSession = config.get('secret.session'); const cfgForceSaveEnable = config.get('autoAssembly.enable'); const cfgForceSaveInterval = ms(config.get('autoAssembly.interval')); @@ -1017,13 +1020,19 @@ function* _createSaveTimer(docId, opt_userId, opt_queue, opt_noDelay) { } } -function checkJwt(docId, token, isSession) { +function checkJwt(docId, token, type) { var res = {decoded: null, description: null, code: null, token: token}; var secret; - if (isSession) { - secret = utils.getSecretByElem(cfgSecretSession); - } else { - secret = utils.getSecret(docId, null, token); + switch (type) { + case commonDefines.c_oAscSecretType.Browser: + secret = utils.getSecret(docId, cfgTokenBrowserSecretFromInbox ? cfgSecretInbox : cfgSecretBrowser, null, token); + break; + case commonDefines.c_oAscSecretType.Inbox: + secret = utils.getSecret(docId, cfgSecretInbox, null, token); + break; + case commonDefines.c_oAscSecretType.Session: + secret = utils.getSecretByElem(cfgSecretSession); + break; } if (undefined == secret) { logger.error('empty secret: docId = %s token = %s', docId, token); @@ -1047,7 +1056,7 @@ function checkJwtHeader(docId, req) { var authorization = req.get(cfgTokenInboxHeader); if (authorization && authorization.startsWith(cfgTokenInboxPrefix)) { var token = authorization.substring(cfgTokenInboxPrefix.length); - return checkJwt(docId, token, false); + return checkJwt(docId, token, commonDefines.c_oAscSecretType.Inbox); } return null; } @@ -1056,7 +1065,7 @@ function checkJwtPayloadHash(docId, hash, body, token) { if (body && Buffer.isBuffer(body)) { var decoded = jwt.decode(token, {complete: true}); var hmac = jwa(decoded.header.alg); - var secret = utils.getSecret(docId, null, token); + var secret = utils.getSecret(docId, cfgSecretInbox, null, token); var signature = hmac.sign(body, secret); res = (hash === signature); } @@ -1178,8 +1187,9 @@ exports.install = function(server, callbackFunction) { conn.sessionTimeLastAction = new Date().getTime() - data.idletime; break; case 'refreshToken' : - var isSession = !!data.jwtSession; - var checkJwtRes = checkJwt(docId, data.jwtSession || data.jwtOpen, isSession); + let secretType = !!data.jwtSession ? commonDefines.c_oAscSecretType.Session : + commonDefines.c_oAscSecretType.Browser; + var checkJwtRes = checkJwt(docId, data.jwtSession || data.jwtOpen, secretType); if (checkJwtRes.decoded) { if (checkJwtRes.decoded.document.key == conn.docId) { sendDataRefreshToken(conn, {token: fillJwtByConnection(conn), expires: cfgTokenSessionExpires}); @@ -1348,7 +1358,7 @@ exports.install = function(server, callbackFunction) { var docIdNew = cmd.getDocId(); //check jwt if (cfgTokenEnableBrowser) { - var checkJwtRes = checkJwt(docIdNew, cmd.getJwt(), false); + var checkJwtRes = checkJwt(docIdNew, cmd.getJwt(), commonDefines.c_oAscSecretType.Browser); if (checkJwtRes.decoded) { fillVersionHistoryFromJwt(checkJwtRes.decoded, cmd); docIdNew = cmd.getDocId(); @@ -1841,8 +1851,9 @@ exports.install = function(server, callbackFunction) { let docId = data.docid; //check jwt if (cfgTokenEnableBrowser) { - const isSession = !!data.jwtSession; - const checkJwtRes = checkJwt(docId, data.jwtSession || data.jwtOpen, isSession); + let secretType = !!data.jwtSession ? commonDefines.c_oAscSecretType.Session : + commonDefines.c_oAscSecretType.Browser; + const checkJwtRes = checkJwt(docId, data.jwtSession || data.jwtOpen, secretType); if (checkJwtRes.decoded) { if (!fillDataFromJwt(checkJwtRes.decoded, data)) { logger.warn("fillDataFromJwt return false: docId = %s", docId); diff --git a/DocService/sources/canvasservice.js b/DocService/sources/canvasservice.js index 9b5f8823..6cc8346c 100644 --- a/DocService/sources/canvasservice.js +++ b/DocService/sources/canvasservice.js @@ -923,7 +923,7 @@ exports.downloadAs = function(req, res) { if (cfgTokenEnableBrowser) { var isValidJwt = false; - var checkJwtRes = docsCoServer.checkJwt(docId, cmd.getJwt(), true); + var checkJwtRes = docsCoServer.checkJwt(docId, cmd.getJwt(), commonDefines.c_oAscSecretType.Session); if (checkJwtRes.decoded) { var doc = checkJwtRes.decoded.document; if (!doc.permissions || (false !== doc.permissions.download || false !== doc.permissions.print)) { diff --git a/DocService/sources/fileuploaderservice.js b/DocService/sources/fileuploaderservice.js index 11a1e262..6969d9be 100644 --- a/DocService/sources/fileuploaderservice.js +++ b/DocService/sources/fileuploaderservice.js @@ -104,7 +104,7 @@ exports.uploadTempFile = function(req, res) { }; function checkJwtUpload(docId, errorName, token){ var res = {err: true, docId: null, userid: null}; - var checkJwtRes = docsCoServer.checkJwt(docId, token, true); + var checkJwtRes = docsCoServer.checkJwt(docId, token, commonDefines.c_oAscSecretType.Session); if (checkJwtRes.decoded) { var doc = checkJwtRes.decoded.document; var edit = checkJwtRes.decoded.editorConfig;