feat: split inbox secret into browser and request part

This commit is contained in:
Sergey Konovalov
2018-02-01 14:18:45 +03:00
parent 4a0fd4857e
commit de6713f766
6 changed files with 39 additions and 20 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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