Security: limit Masterkey remote access (#4017)
* update choose_password to have the confirmation * add comment mark * First version, no test * throw error right away instead of just use masterKey false * fix the logic * move it up before the masterKey check * adding some test * typo * remove the choose_password * newline * add cli options * remove trailing space * handle in case the server is behind proxy * add getting the first ip in the ip list of xff * sanity check the ip in config if it is a valid ip address * split ip extraction to another function * trailing spaces
This commit is contained in:
committed by
Florent Vilmart
parent
811d8b0c7a
commit
7e54265f6d
@@ -133,4 +133,161 @@ describe('middlewares', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not succeed if the ip does not belong to masterKeyIps list', () => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip1','ip2']
|
||||
});
|
||||
fakeReq.ip = 'ip3';
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes);
|
||||
expect(fakeRes.status).toHaveBeenCalledWith(403);
|
||||
});
|
||||
|
||||
it('should succeed if the ip does belong to masterKeyIps list', (done) => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip1','ip2']
|
||||
});
|
||||
fakeReq.ip = 'ip1';
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes,() => {
|
||||
expect(fakeRes.status).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not succeed if the connection.remoteAddress does not belong to masterKeyIps list', () => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip1','ip2']
|
||||
});
|
||||
fakeReq.connection = {remoteAddress : 'ip3'};
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes);
|
||||
expect(fakeRes.status).toHaveBeenCalledWith(403);
|
||||
});
|
||||
|
||||
it('should succeed if the connection.remoteAddress does belong to masterKeyIps list', (done) => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip1','ip2']
|
||||
});
|
||||
fakeReq.connection = {remoteAddress : 'ip1'};
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes,() => {
|
||||
expect(fakeRes.status).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not succeed if the socket.remoteAddress does not belong to masterKeyIps list', () => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip1','ip2']
|
||||
});
|
||||
fakeReq.socket = {remoteAddress : 'ip3'};
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes);
|
||||
expect(fakeRes.status).toHaveBeenCalledWith(403);
|
||||
});
|
||||
|
||||
it('should succeed if the socket.remoteAddress does belong to masterKeyIps list', (done) => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip1','ip2']
|
||||
});
|
||||
fakeReq.socket = {remoteAddress : 'ip1'};
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes,() => {
|
||||
expect(fakeRes.status).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not succeed if the connection.socket.remoteAddress does not belong to masterKeyIps list', () => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip1','ip2']
|
||||
});
|
||||
fakeReq.connection = { socket : {remoteAddress : 'ip3'}};
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes);
|
||||
expect(fakeRes.status).toHaveBeenCalledWith(403);
|
||||
});
|
||||
|
||||
it('should succeed if the connection.socket.remoteAddress does belong to masterKeyIps list', (done) => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip1','ip2']
|
||||
});
|
||||
fakeReq.connection = { socket : {remoteAddress : 'ip1'}};
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes,() => {
|
||||
expect(fakeRes.status).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow any ip to use masterKey if masterKeyIps is empty', (done) => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: []
|
||||
});
|
||||
fakeReq.ip = 'ip1';
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes,() => {
|
||||
expect(fakeRes.status).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should succeed if xff header does belong to masterKeyIps', (done) => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip1']
|
||||
});
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
fakeReq.headers['x-forwarded-for'] = 'ip1, ip2, ip3';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes,() => {
|
||||
expect(fakeRes.status).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should succeed if xff header with one ip does belong to masterKeyIps', (done) => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip1']
|
||||
});
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
fakeReq.headers['x-forwarded-for'] = 'ip1';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes,() => {
|
||||
expect(fakeRes.status).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not succeed if xff header does not belong to masterKeyIps', () => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip4']
|
||||
});
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
fakeReq.headers['x-forwarded-for'] = 'ip1, ip2, ip3';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes);
|
||||
expect(fakeRes.status).toHaveBeenCalledWith(403);
|
||||
});
|
||||
|
||||
it('should not succeed if xff header is empty and masterKeyIps is set', () => {
|
||||
AppCache.put(fakeReq.body._ApplicationId, {
|
||||
masterKey: 'masterKey',
|
||||
masterKeyIps: ['ip1']
|
||||
});
|
||||
fakeReq.headers['x-parse-master-key'] = 'masterKey';
|
||||
fakeReq.headers['x-forwarded-for'] = '';
|
||||
middlewares.handleParseHeaders(fakeReq, fakeRes);
|
||||
expect(fakeRes.status).toHaveBeenCalledWith(403);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -419,4 +419,18 @@ describe('server', () => {
|
||||
reconfigureServer({ revokeSessionOnPasswordReset: 'non-bool' })
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('fails if you provides invalid ip in masterKeyIps', done => {
|
||||
reconfigureServer({ masterKeyIps: ['invalidIp','1.2.3.4'] })
|
||||
.catch(error => {
|
||||
expect(error).toEqual('Invalid ip in masterKeyIps: invalidIp');
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
it('should suceed if you provide valid ip in masterKeyIps', done => {
|
||||
reconfigureServer({ masterKeyIps: ['1.2.3.4','2001:0db8:0000:0042:0000:8a2e:0370:7334'] })
|
||||
.then(done)
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user