mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-02-10 18:05:07 +08:00
[jwt] Validate required parameters of browser token
This commit is contained in:
committed by
Sergey Konovalov
parent
733a941d59
commit
b4d72bc7f8
39
DocService/npm-shrinkwrap.json
generated
39
DocService/npm-shrinkwrap.json
generated
@ -28,6 +28,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "8.9.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz",
|
||||
"integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"apicache": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/apicache/-/apicache-1.6.2.tgz",
|
||||
@ -433,6 +444,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"faye-websocket": {
|
||||
"version": "0.11.4",
|
||||
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
|
||||
@ -512,6 +528,11 @@
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"json5": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "http://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
||||
@ -846,6 +867,11 @@
|
||||
"ipaddr.js": "1.9.1"
|
||||
}
|
||||
},
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
@ -920,6 +946,11 @@
|
||||
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-1.3.0.tgz",
|
||||
"integrity": "sha1-gG6+e7+3005NfB6e8oLvz60EEmo="
|
||||
},
|
||||
"require-from-string": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
|
||||
},
|
||||
"retry": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
||||
@ -1095,6 +1126,14 @@
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"utf7": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/utf7/-/utf7-1.0.2.tgz",
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
"prepare4shutdown": "sources/shutdown.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "^8.9.0",
|
||||
"apicache": "^1.6.2",
|
||||
"base64-stream": "^1.0.0",
|
||||
"body-parser": "^1.18.3",
|
||||
|
||||
@ -105,6 +105,8 @@ const wopiClient = require('./wopiClient');
|
||||
const queueService = require('./../../Common/sources/taskqueueRabbitMQ');
|
||||
const rabbitMQCore = require('./../../Common/sources/rabbitMQCore');
|
||||
const activeMQCore = require('./../../Common/sources/activeMQCore');
|
||||
const Ajv = require("ajv");
|
||||
const openingFileSchema = require("../../schema/json-api/opening-file.json");
|
||||
|
||||
const editorDataStorage = require('./' + configCommon.get('services.CoAuthoring.server.editorDataStorage'));
|
||||
let cfgEditor = JSON.parse(JSON.stringify(config.get('editor')));
|
||||
@ -181,6 +183,9 @@ const PRECISION = [{name: 'hour', val: ms('1h')}, {name: 'day', val: ms('1d')},
|
||||
{name: 'month', val: ms('31d')},
|
||||
];
|
||||
|
||||
const ajv = new Ajv();
|
||||
const ajvValidate = ajv.compile(openingFileSchema);
|
||||
|
||||
function getIsShutdown() {
|
||||
return shutdownFlag;
|
||||
}
|
||||
@ -1940,93 +1945,81 @@ exports.install = function(server, callbackFunction) {
|
||||
//not '=' because if it jwt from previous version, we must use values from data
|
||||
Object.assign(data.permissions, permissions);
|
||||
}
|
||||
|
||||
//issuer for secret
|
||||
if (decoded.iss) {
|
||||
data.iss = decoded.iss;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
function fillDataFromJwt(decoded, data) {
|
||||
let res = true;
|
||||
var openCmd = data.openCmd;
|
||||
if (decoded.document) {
|
||||
var doc = decoded.document;
|
||||
if(null != doc.key){
|
||||
data.docid = doc.key;
|
||||
if(openCmd){
|
||||
openCmd.id = doc.key;
|
||||
var doc = decoded.document;
|
||||
data.docid = doc.key;
|
||||
if (openCmd) {
|
||||
openCmd.id = doc.key;
|
||||
}
|
||||
if (doc.permissions) {
|
||||
res = deepEqual(data.permissions, doc.permissions, {strict: true});
|
||||
if (!data.permissions) {
|
||||
data.permissions = {};
|
||||
}
|
||||
//not '=' because if it jwt from previous version, we must use values from data
|
||||
Object.assign(data.permissions, doc.permissions);
|
||||
}
|
||||
if (openCmd) {
|
||||
if (null != doc.fileType) {
|
||||
openCmd.format = doc.fileType;
|
||||
}
|
||||
if (null != doc.title) {
|
||||
openCmd.title = doc.title;
|
||||
}
|
||||
openCmd.url = doc.url;
|
||||
}
|
||||
if (null != doc.ds_encrypted) {
|
||||
data.encrypted = doc.ds_encrypted;
|
||||
}
|
||||
var edit = decoded.editorConfig;
|
||||
data.documentCallbackUrl = edit.callbackUrl;
|
||||
if (null != edit.lang) {
|
||||
data.lang = edit.lang;
|
||||
}
|
||||
if (null != edit.mode) {
|
||||
data.mode = edit.mode;
|
||||
}
|
||||
if (null != edit.ds_view) {
|
||||
data.view = edit.ds_view;
|
||||
}
|
||||
if (null != edit.ds_isCloseCoAuthoring) {
|
||||
data.isCloseCoAuthoring = edit.ds_isCloseCoAuthoring;
|
||||
}
|
||||
data.isEnterCorrectPassword = edit.ds_isEnterCorrectPassword;
|
||||
data.denyChangeName = edit.ds_denyChangeName;
|
||||
if (edit.user) {
|
||||
var dataUser = data.user;
|
||||
var user = edit.user;
|
||||
if (null != user.id) {
|
||||
dataUser.id = user.id;
|
||||
if (openCmd) {
|
||||
openCmd.userid = user.id;
|
||||
}
|
||||
}
|
||||
if(doc.permissions) {
|
||||
res = deepEqual(data.permissions, doc.permissions, {strict: true});
|
||||
if(!data.permissions){
|
||||
data.permissions = {};
|
||||
}
|
||||
//not '=' because if it jwt from previous version, we must use values from data
|
||||
Object.assign(data.permissions, doc.permissions);
|
||||
if (null != user.index) {
|
||||
dataUser.indexUser = user.index;
|
||||
}
|
||||
if(openCmd){
|
||||
if(null != doc.fileType) {
|
||||
openCmd.format = doc.fileType;
|
||||
}
|
||||
if(null != doc.title) {
|
||||
openCmd.title = doc.title;
|
||||
}
|
||||
if(null != doc.url) {
|
||||
openCmd.url = doc.url;
|
||||
}
|
||||
if (null != user.firstname) {
|
||||
dataUser.firstname = user.firstname;
|
||||
}
|
||||
if (null != doc.ds_encrypted) {
|
||||
data.encrypted = doc.ds_encrypted;
|
||||
if (null != user.lastname) {
|
||||
dataUser.lastname = user.lastname;
|
||||
}
|
||||
if (user.name) {
|
||||
dataUser.username = user.name;
|
||||
}
|
||||
}
|
||||
if (decoded.editorConfig) {
|
||||
var edit = decoded.editorConfig;
|
||||
if (null != edit.callbackUrl) {
|
||||
data.documentCallbackUrl = edit.callbackUrl;
|
||||
}
|
||||
if (null != edit.lang) {
|
||||
data.lang = edit.lang;
|
||||
}
|
||||
if (null != edit.mode) {
|
||||
data.mode = edit.mode;
|
||||
}
|
||||
if (null != edit.ds_view) {
|
||||
data.view = edit.ds_view;
|
||||
}
|
||||
if (null != edit.ds_isCloseCoAuthoring) {
|
||||
data.isCloseCoAuthoring = edit.ds_isCloseCoAuthoring;
|
||||
}
|
||||
data.isEnterCorrectPassword = edit.ds_isEnterCorrectPassword;
|
||||
data.denyChangeName = edit.ds_denyChangeName;
|
||||
if (edit.user) {
|
||||
var dataUser = data.user;
|
||||
var user = edit.user;
|
||||
if (null != user.id) {
|
||||
dataUser.id = user.id;
|
||||
if (openCmd) {
|
||||
openCmd.userid = user.id;
|
||||
}
|
||||
}
|
||||
if (null != user.index) {
|
||||
dataUser.indexUser = user.index;
|
||||
}
|
||||
if (null != user.firstname) {
|
||||
dataUser.firstname = user.firstname;
|
||||
}
|
||||
if (null != user.lastname) {
|
||||
dataUser.lastname = user.lastname;
|
||||
}
|
||||
if (user.name) {
|
||||
dataUser.username = user.name;
|
||||
}
|
||||
}
|
||||
if (edit.user && edit.user.name) {
|
||||
data.denyChangeName = true;
|
||||
}
|
||||
}
|
||||
|
||||
res = res && fillDataFromWopiJwt(decoded, data);
|
||||
|
||||
//todo make required fields
|
||||
if (decoded.url || decoded.payload|| (decoded.key && !decoded.fileInfo)) {
|
||||
res = false;
|
||||
if (edit.user && edit.user.name) {
|
||||
data.denyChangeName = true;
|
||||
}
|
||||
|
||||
//issuer for secret
|
||||
@ -2073,7 +2066,26 @@ exports.install = function(server, callbackFunction) {
|
||||
commonDefines.c_oAscSecretType.Browser;
|
||||
const checkJwtRes = checkJwt(docId, data.jwtSession || data.jwtOpen, secretType);
|
||||
if (checkJwtRes.decoded) {
|
||||
if (!fillDataFromJwt(checkJwtRes.decoded, data)) {
|
||||
let decoded = checkJwtRes.decoded;
|
||||
let fillDataFromJwtRes = false;
|
||||
if (decoded.fileInfo) {
|
||||
//wopi
|
||||
fillDataFromJwtRes = fillDataFromWopiJwt(decoded, data);
|
||||
} else if (decoded.editorConfig && undefined !== decoded.editorConfig.ds_view) {
|
||||
//reconnection
|
||||
fillDataFromJwtRes = fillDataFromJwt(decoded, data);
|
||||
} else {
|
||||
//opening
|
||||
let valid = ajvValidate(decoded);
|
||||
if (valid) {
|
||||
fillDataFromJwtRes = fillDataFromJwt(decoded, data);
|
||||
} else {
|
||||
logger.error("auth missing required parameter (since 7.1 version): docId = %s %j", docId, ajvValidate.errors);
|
||||
conn.close(constants.JWT_ERROR_CODE, constants.JWT_ERROR_REASON);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!fillDataFromJwtRes) {
|
||||
logger.warn("fillDataFromJwt return false: docId = %s", docId);
|
||||
conn.close(constants.ACCESS_DENIED_CODE, constants.ACCESS_DENIED_REASON);
|
||||
return;
|
||||
|
||||
@ -1081,7 +1081,7 @@ function* commandSfcCallback(cmd, isSfcm, isEncrypted) {
|
||||
if (!isSfcm) {
|
||||
//cleanupRes can be false in case of simultaneous opening. it is OK
|
||||
let cleanupRes = yield cleanupCacheIf(updateMask);
|
||||
logger.debug('storeForgotten cleanupRes=%s', cleanupRes);
|
||||
logger.debug('storeForgotten cleanupRes=%s: docId = %s', cleanupRes, docId);
|
||||
}
|
||||
}
|
||||
if (forceSave) {
|
||||
|
||||
86
schema/json-api/opening-file.json
Normal file
86
schema/json-api/opening-file.json
Normal file
@ -0,0 +1,86 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"$id": "https://example.com/example.json",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"document",
|
||||
"editorConfig"
|
||||
],
|
||||
"properties": {
|
||||
"document": {
|
||||
"$id": "#/properties/document",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"key",
|
||||
"permissions",
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"key": {
|
||||
"$id": "#/properties/document/properties/key",
|
||||
"type": "string"
|
||||
},
|
||||
"permissions": {
|
||||
"$id": "#/properties/document/properties/permissions",
|
||||
"type": "object",
|
||||
"required": [],
|
||||
"additionalProperties": true
|
||||
},
|
||||
"url": {
|
||||
"$id": "#/properties/document/properties/url",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
"editorConfig": {
|
||||
"$id": "#/properties/editorConfig",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"callbackUrl",
|
||||
"mode"
|
||||
],
|
||||
"properties": {
|
||||
"callbackUrl": {
|
||||
"$id": "#/properties/editorConfig/properties/callbackUrl",
|
||||
"type": "string"
|
||||
},
|
||||
"mode": {
|
||||
"$id": "#/properties/editorConfig/properties/mode",
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"$id": "#/properties/editorConfig/properties/user",
|
||||
"type": "object",
|
||||
"required": [],
|
||||
"properties": {
|
||||
"group": {
|
||||
"$id": "#/properties/editorConfig/properties/user/properties/group",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"$id": "#/properties/editorConfig/properties/user/properties/id",
|
||||
"anyOf": [
|
||||
{
|
||||
"$id": "#/properties/editorConfig/properties/user/properties/id/anyOf/0",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"$id": "#/properties/editorConfig/properties/user/properties/id/anyOf/1",
|
||||
"type": "integer"
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"$id": "#/properties/editorConfig/properties/user/properties/name",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
Reference in New Issue
Block a user