mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-06 22:40:14 -05:00
Added spam prevention for v2 sessions (#10030)
no-issue - Added spam prevention to POST /session - This blocks repeated requests the the /session endpoint preventing brute force password attacks - Updated session controller to reset brute middleware - This updates the session controller to reset the brute force protection on a successful login. This is required so that a user is not locked out forever :o!!
This commit is contained in:
parent
fd958addb6
commit
ae71f2deca
3 changed files with 47 additions and 5 deletions
|
@ -25,8 +25,13 @@ const session = {
|
||||||
password: object.password
|
password: object.password
|
||||||
}).then((user) => {
|
}).then((user) => {
|
||||||
return Promise.resolve((req, res, next) => {
|
return Promise.resolve((req, res, next) => {
|
||||||
req.user = user;
|
req.brute.reset(function (err) {
|
||||||
auth.session.createSession(req, res, next);
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
req.user = user;
|
||||||
|
auth.session.createSession(req, res, next);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
throw new common.errors.UnauthorizedError({
|
throw new common.errors.UnauthorizedError({
|
||||||
|
|
|
@ -148,7 +148,11 @@ module.exports = function apiRoutes() {
|
||||||
// ## Sessions
|
// ## Sessions
|
||||||
router.get('/session', mw.authAdminAPI, api.http(apiv2.session.read));
|
router.get('/session', mw.authAdminAPI, api.http(apiv2.session.read));
|
||||||
// We don't need auth when creating a new session (logging in)
|
// We don't need auth when creating a new session (logging in)
|
||||||
router.post('/session', api.http(apiv2.session.add));
|
router.post('/session',
|
||||||
|
shared.middlewares.brute.globalBlock,
|
||||||
|
shared.middlewares.brute.userLogin,
|
||||||
|
api.http(apiv2.session.add)
|
||||||
|
);
|
||||||
router.del('/session', mw.authAdminAPI, api.http(apiv2.session.delete));
|
router.del('/session', mw.authAdminAPI, api.http(apiv2.session.delete));
|
||||||
|
|
||||||
// ## Authentication
|
// ## Authentication
|
||||||
|
|
|
@ -49,8 +49,12 @@ describe('Session controller', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('it returns a function that sets req.user and calls createSession if the check works', function () {
|
it('it returns a function that calls req.brute.reset, sets req.user and calls createSession if the check works', function () {
|
||||||
const fakeReq = {};
|
const fakeReq = {
|
||||||
|
brute: {
|
||||||
|
reset: sandbox.stub().callsArg(0)
|
||||||
|
}
|
||||||
|
};
|
||||||
const fakeRes = {};
|
const fakeRes = {};
|
||||||
const fakeNext = () => {};
|
const fakeNext = () => {};
|
||||||
const fakeUser = models.User.forge({});
|
const fakeUser = models.User.forge({});
|
||||||
|
@ -65,6 +69,8 @@ describe('Session controller', function () {
|
||||||
}, {}).then((fn) => {
|
}, {}).then((fn) => {
|
||||||
fn(fakeReq, fakeRes, fakeNext);
|
fn(fakeReq, fakeRes, fakeNext);
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
|
should.equal(fakeReq.brute.reset.callCount, 1);
|
||||||
|
|
||||||
const createSessionStubCall = createSessionStub.getCall(0);
|
const createSessionStubCall = createSessionStub.getCall(0);
|
||||||
should.equal(fakeReq.user, fakeUser);
|
should.equal(fakeReq.user, fakeUser);
|
||||||
should.equal(createSessionStubCall.args[0], fakeReq);
|
should.equal(createSessionStubCall.args[0], fakeReq);
|
||||||
|
@ -72,6 +78,33 @@ describe('Session controller', function () {
|
||||||
should.equal(createSessionStubCall.args[2], fakeNext);
|
should.equal(createSessionStubCall.args[2], fakeNext);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('it returns a function that calls req.brute.reset and calls next if reset errors', function () {
|
||||||
|
const resetError = new Error();
|
||||||
|
const fakeReq = {
|
||||||
|
brute: {
|
||||||
|
reset: sandbox.stub().callsArgWith(0, resetError)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const fakeRes = {};
|
||||||
|
const fakeNext = sandbox.stub();
|
||||||
|
const fakeUser = models.User.forge({});
|
||||||
|
sandbox.stub(models.User, 'check')
|
||||||
|
.resolves(fakeUser);
|
||||||
|
|
||||||
|
const createSessionStub = sandbox.stub(sessionServiceMiddleware, 'createSession');
|
||||||
|
|
||||||
|
return sessionController.add({
|
||||||
|
username: 'freddy@vodafone.com',
|
||||||
|
password: 'qu33nRul35'
|
||||||
|
}, {}).then((fn) => {
|
||||||
|
fn(fakeReq, fakeRes, fakeNext);
|
||||||
|
}).then(function () {
|
||||||
|
should.equal(fakeReq.brute.reset.callCount, 1);
|
||||||
|
should.equal(fakeNext.callCount, 1);
|
||||||
|
should.equal(fakeNext.args[0][0], resetError);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#delete', function () {
|
describe('#delete', function () {
|
||||||
|
|
Loading…
Reference in a new issue