Skip to content

Commit 63f7468

Browse files
committed
Merge pull request #753 from ParsePlatform/nlutsenko.middleware.routers
Use shared middleware to enforce masterkey security on logs/global config/hooks APIs.
2 parents 92e51ab + 17235b5 commit 63f7468

File tree

5 files changed

+36
-67
lines changed

5 files changed

+36
-67
lines changed

spec/LogsRouter.spec.js

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
'use strict';
2+
3+
const request = require('request');
14
var LogsRouter = require('../src/Routers/LogsRouter').LogsRouter;
25
var LoggerController = require('../src/Controllers/LoggerController').LoggerController;
36
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
@@ -45,23 +48,18 @@ describe('LogsRouter', () => {
4548
done();
4649
});
4750

48-
it('can check invalid master key of request', (done) => {
49-
// Make mock request
50-
var request = {
51-
auth: {
52-
isMaster: false
53-
},
54-
query: {},
55-
config: {
56-
loggerController: loggerController
51+
it('can check invalid master key of request', done => {
52+
request.get({
53+
url: 'http://localhost:8378/1/logs',
54+
json: true,
55+
headers: {
56+
'X-Parse-Application-Id': 'test',
57+
'X-Parse-REST-API-Key': 'rest'
5758
}
58-
};
59-
60-
var router = new LogsRouter();
61-
62-
expect(() => {
63-
router.handleGET(request);
64-
}).toThrow();
65-
done();
59+
}, (error, response, body) => {
60+
expect(response.statusCode).toEqual(403);
61+
expect(body.error).toEqual('unauthorized: master key is required');
62+
done();
63+
});
6664
});
6765
});

spec/ParseGlobalConfig.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ describe('a GlobalConfig', () => {
5353
'X-Parse-REST-API-Key': 'rest'
5454
},
5555
}, (error, response, body) => {
56-
expect(response.statusCode).toEqual(401);
57-
expect(body.error).toEqual('unauthorized');
56+
expect(response.statusCode).toEqual(403);
57+
expect(body.error).toEqual('unauthorized: master key is required');
5858
done();
5959
});
6060
});

src/Routers/GlobalConfigRouter.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var Parse = require('parse/node').Parse;
44

55
import PromiseRouter from '../PromiseRouter';
6+
import * as middleware from "../middlewares";
67

78
export class GlobalConfigRouter extends PromiseRouter {
89
getGlobalConfig(req) {
@@ -18,13 +19,6 @@ export class GlobalConfigRouter extends PromiseRouter {
1819
}));
1920
}
2021
updateGlobalConfig(req) {
21-
if (!req.auth.isMaster) {
22-
return Promise.resolve({
23-
status: 401,
24-
response: {error: 'unauthorized'},
25-
});
26-
}
27-
2822
return req.config.database.rawCollection('_GlobalConfig')
2923
.then(coll => coll.findOneAndUpdate({ _id: 1 }, { $set: req.body }))
3024
.then(response => {
@@ -41,7 +35,7 @@ export class GlobalConfigRouter extends PromiseRouter {
4135

4236
mountRoutes() {
4337
this.route('GET', '/config', req => { return this.getGlobalConfig(req) });
44-
this.route('PUT', '/config', req => { return this.updateGlobalConfig(req) });
38+
this.route('PUT', '/config', middleware.promiseEnforceMasterKeyAccess, req => { return this.updateGlobalConfig(req) });
4539
}
4640
}
4741

src/Routers/HooksRouter.js

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
import { Parse } from 'parse/node';
22
import PromiseRouter from '../PromiseRouter';
33
import { HooksController } from '../Controllers/HooksController';
4-
5-
function enforceMasterKeyAccess(req) {
6-
if (!req.auth.isMaster) {
7-
throw new Parse.Error(403, "unauthorized: master key is required");
8-
}
9-
}
4+
import * as middleware from "../middlewares";
105

116
export class HooksRouter extends PromiseRouter {
12-
137
createHook(aHook, config) {
148
return config.hooksController.createHook(aHook).then( (hook) => ({response: hook}));
159
};
@@ -93,14 +87,14 @@ export class HooksRouter extends PromiseRouter {
9387
}
9488

9589
mountRoutes() {
96-
this.route('GET', '/hooks/functions', enforceMasterKeyAccess, this.handleGetFunctions.bind(this));
97-
this.route('GET', '/hooks/triggers', enforceMasterKeyAccess, this.handleGetTriggers.bind(this));
98-
this.route('GET', '/hooks/functions/:functionName', enforceMasterKeyAccess, this.handleGetFunctions.bind(this));
99-
this.route('GET', '/hooks/triggers/:className/:triggerName', enforceMasterKeyAccess, this.handleGetTriggers.bind(this));
100-
this.route('POST', '/hooks/functions', enforceMasterKeyAccess, this.handlePost.bind(this));
101-
this.route('POST', '/hooks/triggers', enforceMasterKeyAccess, this.handlePost.bind(this));
102-
this.route('PUT', '/hooks/functions/:functionName', enforceMasterKeyAccess, this.handlePut.bind(this));
103-
this.route('PUT', '/hooks/triggers/:className/:triggerName', enforceMasterKeyAccess, this.handlePut.bind(this));
90+
this.route('GET', '/hooks/functions', middleware.promiseEnforceMasterKeyAccess, this.handleGetFunctions.bind(this));
91+
this.route('GET', '/hooks/triggers', middleware.promiseEnforceMasterKeyAccess, this.handleGetTriggers.bind(this));
92+
this.route('GET', '/hooks/functions/:functionName', middleware.promiseEnforceMasterKeyAccess, this.handleGetFunctions.bind(this));
93+
this.route('GET', '/hooks/triggers/:className/:triggerName', middleware.promiseEnforceMasterKeyAccess, this.handleGetTriggers.bind(this));
94+
this.route('POST', '/hooks/functions', middleware.promiseEnforceMasterKeyAccess, this.handlePost.bind(this));
95+
this.route('POST', '/hooks/triggers', middleware.promiseEnforceMasterKeyAccess, this.handlePost.bind(this));
96+
this.route('PUT', '/hooks/functions/:functionName', middleware.promiseEnforceMasterKeyAccess, this.handlePut.bind(this));
97+
this.route('PUT', '/hooks/triggers/:className/:triggerName', middleware.promiseEnforceMasterKeyAccess, this.handlePut.bind(this));
10498
}
10599
}
106100

src/Routers/LogsRouter.js

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,11 @@
11
import { Parse } from 'parse/node';
22
import PromiseRouter from '../PromiseRouter';
3-
4-
// only allow request with master key
5-
let enforceSecurity = (auth) => {
6-
if (!auth || !auth.isMaster) {
7-
throw new Parse.Error(
8-
Parse.Error.OPERATION_FORBIDDEN,
9-
'Clients aren\'t allowed to perform the ' +
10-
'get' + ' operation on logs.'
11-
);
12-
}
13-
}
3+
import * as middleware from "../middlewares";
144

155
export class LogsRouter extends PromiseRouter {
166

177
mountRoutes() {
18-
this.route('GET','/logs', (req) => {
19-
return this.handleGET(req);
20-
});
8+
this.route('GET','/logs', middleware.promiseEnforceMasterKeyAccess, req => { return this.handleGET(req); });
219
}
2210

2311
// Returns a promise for a {response} object.
@@ -29,31 +17,26 @@ export class LogsRouter extends PromiseRouter {
2917
// size (optional) Number of rows returned by search. Defaults to 10
3018
handleGET(req) {
3119
if (!req.config || !req.config.loggerController) {
32-
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
33-
'Logger adapter is not availabe');
20+
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED, 'Logger adapter is not available.');
3421
}
3522

36-
let promise = new Parse.Promise();
3723
let from = req.query.from;
3824
let until = req.query.until;
3925
let size = req.query.size;
4026
let order = req.query.order
4127
let level = req.query.level;
42-
enforceSecurity(req.auth);
4328

4429
const options = {
4530
from,
4631
until,
4732
size,
4833
order,
49-
level,
50-
}
34+
level
35+
};
5136

52-
return req.config.loggerController.getLogs(options).then((result) => {
53-
return Promise.resolve({
54-
response: result
55-
});
56-
})
37+
return req.config.loggerController
38+
.getLogs(options)
39+
.then(result => ({ response: result }));
5740
}
5841
}
5942

0 commit comments

Comments
 (0)