mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 05:37:34 +03:00
Added easy way to enable admin api key authentication
refs #9865 - small refactoring to make both session and admin api key handling similar - admin api key authentication is still disabled, but easy to enable - added proof test how to authenticate using admin api keys
This commit is contained in:
parent
4f7783939d
commit
1126997244
@ -35,9 +35,10 @@ const _extractTokenFromHeader = function extractTokenFromHeader(header) {
|
||||
* https://tools.ietf.org/html/rfc7519#section-4.1.3
|
||||
*/
|
||||
const authenticate = (req, res, next) => {
|
||||
// we don't have an Authorization header so allow fallthrough to other
|
||||
// CASE: we don't have an Authorization header so allow fallthrough to other
|
||||
// auth middleware or final "ensure authenticated" check
|
||||
if (!req.headers || !req.headers.authorization) {
|
||||
req.api_key = null;
|
||||
return next();
|
||||
}
|
||||
|
||||
|
@ -102,9 +102,10 @@ const authenticate = {
|
||||
)(req, res, next);
|
||||
},
|
||||
|
||||
// ### v2 API auth middleware
|
||||
authenticateAdminApi: [session.safeGetSession, session.getUser],
|
||||
authenticateAdminApiKey: apiKeyAuth.admin.authenticateAdminApiKey,
|
||||
// @NOTE: authentication for admin api keys is disabled
|
||||
// authenticateAdminApi: [apiKeyAuth.admin.authenticate, session.authenticate],
|
||||
authenticateAdminApi: [session.authenticate],
|
||||
|
||||
authenticateContentApi: [apiKeyAuth.content.authenticateContentApiKey, members.authenticateMembersToken]
|
||||
};
|
||||
|
||||
|
@ -1,16 +1,5 @@
|
||||
module.exports = {
|
||||
get getSession() {
|
||||
return require('./middleware').getSession;
|
||||
},
|
||||
|
||||
get cookieCsrfProtection() {
|
||||
return require('./middleware').cookieCsrfProtection;
|
||||
},
|
||||
|
||||
get safeGetSession() {
|
||||
return require('./middleware').safeGetSession;
|
||||
},
|
||||
|
||||
// @TODO: expose files/units and not functions of units
|
||||
get createSession() {
|
||||
return require('./middleware').createSession;
|
||||
},
|
||||
@ -19,7 +8,7 @@ module.exports = {
|
||||
return require('./middleware').destroySession;
|
||||
},
|
||||
|
||||
get getUser() {
|
||||
return require('./middleware').getUser;
|
||||
get authenticate() {
|
||||
return require('./middleware').authenticate;
|
||||
}
|
||||
};
|
||||
|
@ -1,10 +1,10 @@
|
||||
const url = require('url');
|
||||
const session = require('express-session');
|
||||
const common = require('../../../lib/common');
|
||||
const constants = require('../../../lib/constants');
|
||||
const config = require('../../../config');
|
||||
const settingsCache = require('../../settings/cache');
|
||||
const models = require('../../../models');
|
||||
const session = require('express-session');
|
||||
const SessionStore = require('./store');
|
||||
const urlService = require('../../url');
|
||||
|
||||
@ -76,46 +76,65 @@ const destroySession = (req, res, next) => {
|
||||
});
|
||||
};
|
||||
|
||||
const getUser = (req, res, next) => {
|
||||
if (!req.session || !req.session.user_id) {
|
||||
req.user = null;
|
||||
return next();
|
||||
}
|
||||
models.User.findOne({id: req.session.user_id})
|
||||
.then((user) => {
|
||||
req.user = user;
|
||||
next();
|
||||
}).catch(() => {
|
||||
req.user = null;
|
||||
next();
|
||||
});
|
||||
};
|
||||
|
||||
const cookieCsrfProtection = (req, res, next) => {
|
||||
const cookieCsrfProtection = (req) => {
|
||||
// If there is no origin on the session object it means this is a *new*
|
||||
// session, that hasn't been initialised yet. So we don't need CSRF protection
|
||||
if (!req.session.origin) {
|
||||
return next();
|
||||
return;
|
||||
}
|
||||
|
||||
const origin = getOrigin(req);
|
||||
|
||||
if (req.session.origin !== origin) {
|
||||
return next(new common.errors.BadRequestError({
|
||||
throw new common.errors.BadRequestError({
|
||||
message: common.i18n.t('errors.middleware.auth.mismatchedOrigin', {
|
||||
expected: req.session.origin,
|
||||
actual: origin
|
||||
})
|
||||
}));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const authenticate = (req, res, next) => {
|
||||
// CASE: we don't have a cookie header so allow fallthrough to other
|
||||
// auth middleware or final "ensure authenticated" check
|
||||
if (!req.headers || !req.headers.cookie) {
|
||||
req.user = null;
|
||||
return next();
|
||||
}
|
||||
|
||||
return next();
|
||||
getSession(req, res, function (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
try {
|
||||
cookieCsrfProtection(req);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (!req.session || !req.session.user_id) {
|
||||
req.user = null;
|
||||
return next();
|
||||
}
|
||||
|
||||
models.User.findOne({id: req.session.user_id})
|
||||
.then((user) => {
|
||||
req.user = user;
|
||||
next();
|
||||
})
|
||||
.catch(() => {
|
||||
req.user = null;
|
||||
next();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// @TODO: this interface exposes private functions
|
||||
module.exports = exports = {
|
||||
getSession,
|
||||
cookieCsrfProtection,
|
||||
safeGetSession: [getSession, cookieCsrfProtection],
|
||||
createSession,
|
||||
destroySession,
|
||||
getUser
|
||||
cookieCsrfProtection,
|
||||
authenticate
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,4 @@
|
||||
const sessionService = require('../../../../../server/services/auth/session');
|
||||
const SessionStore = require('../../../../../server/services/auth/session/store');
|
||||
const config = require('../../../../../server/config');
|
||||
const sessionMiddleware = require('../../../../../server/services/auth/session/middleware');
|
||||
const models = require('../../../../../server/models');
|
||||
const sinon = require('sinon');
|
||||
const should = require('should');
|
||||
@ -44,7 +42,7 @@ describe('Session Service', function () {
|
||||
.withArgs('origin').returns('')
|
||||
.withArgs('referrer').returns('');
|
||||
|
||||
sessionService.createSession(req, fakeRes(), function next(err) {
|
||||
sessionMiddleware.createSession(req, fakeRes(), function next(err) {
|
||||
should.equal(err instanceof BadRequestError, true);
|
||||
done();
|
||||
});
|
||||
@ -68,7 +66,7 @@ describe('Session Service', function () {
|
||||
done();
|
||||
});
|
||||
|
||||
sessionService.createSession(req, res);
|
||||
sessionMiddleware.createSession(req, res);
|
||||
});
|
||||
|
||||
it('sets req.session.user_id,origin,user_agent,ip and calls sendStatus with 201 if the check succeeds', function (done) {
|
||||
@ -92,7 +90,7 @@ describe('Session Service', function () {
|
||||
done();
|
||||
});
|
||||
|
||||
sessionService.createSession(req, res);
|
||||
sessionMiddleware.createSession(req, res);
|
||||
});
|
||||
});
|
||||
|
||||
@ -102,7 +100,7 @@ describe('Session Service', function () {
|
||||
const res = fakeRes();
|
||||
const destroyStub = sandbox.stub(req.session, 'destroy');
|
||||
|
||||
sessionService.destroySession(req, res);
|
||||
sessionMiddleware.destroySession(req, res);
|
||||
|
||||
should.equal(destroyStub.callCount, 1);
|
||||
});
|
||||
@ -115,7 +113,7 @@ describe('Session Service', function () {
|
||||
fn(new Error('oops'));
|
||||
});
|
||||
|
||||
sessionService.destroySession(req, res, function next(err) {
|
||||
sessionMiddleware.destroySession(req, res, function next(err) {
|
||||
should.equal(err instanceof InternalServerError, true);
|
||||
done();
|
||||
});
|
||||
@ -134,71 +132,7 @@ describe('Session Service', function () {
|
||||
done();
|
||||
});
|
||||
|
||||
sessionService.destroySession(req, res);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUser', function () {
|
||||
it('sets req.user to null and calls next if there is no session', function (done) {
|
||||
const req = fakeReq();
|
||||
const res = fakeRes();
|
||||
|
||||
delete req.session;
|
||||
|
||||
sessionService.getUser(req, res, function next() {
|
||||
should.equal(req.user, null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('sets req.user to null and calls next if there is no session', function (done) {
|
||||
const req = fakeReq();
|
||||
const res = fakeRes();
|
||||
|
||||
sessionService.getUser(req, res, function next() {
|
||||
should.equal(req.user, null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('calls User.findOne with id set to req.session.user_id', function (done) {
|
||||
const req = fakeReq();
|
||||
const res = fakeRes();
|
||||
sandbox.stub(models.User, 'findOne')
|
||||
.callsFake(function (opts) {
|
||||
should.equal(opts.id, 23);
|
||||
done();
|
||||
});
|
||||
|
||||
req.session.user_id = 23;
|
||||
sessionService.getUser(req, res);
|
||||
});
|
||||
|
||||
it('sets req.user to null and calls next if the user is not found', function (done) {
|
||||
const req = fakeReq();
|
||||
const res = fakeRes();
|
||||
sandbox.stub(models.User, 'findOne')
|
||||
.rejects();
|
||||
|
||||
req.session.user_id = 23;
|
||||
sessionService.getUser(req, res, function next() {
|
||||
should.equal(req.user, null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('calls next after settign req.user to the found user', function (done) {
|
||||
const req = fakeReq();
|
||||
const res = fakeRes();
|
||||
const user = models.User.forge({id: 23});
|
||||
sandbox.stub(models.User, 'findOne')
|
||||
.resolves(user);
|
||||
|
||||
req.session.user_id = 23;
|
||||
sessionService.getUser(req, res, function next() {
|
||||
should.equal(req.user, user);
|
||||
done();
|
||||
});
|
||||
sessionMiddleware.destroySession(req, res);
|
||||
});
|
||||
});
|
||||
|
||||
@ -207,10 +141,8 @@ describe('Session Service', function () {
|
||||
const req = fakeReq();
|
||||
const res = fakeRes();
|
||||
|
||||
sessionService.cookieCsrfProtection(req, res, function next(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
sessionMiddleware.cookieCsrfProtection(req);
|
||||
done();
|
||||
});
|
||||
|
||||
it('calls next if req origin matches the session origin', function (done) {
|
||||
@ -220,10 +152,8 @@ describe('Session Service', function () {
|
||||
.withArgs('origin').returns('http://host.tld');
|
||||
req.session.origin = 'http://host.tld';
|
||||
|
||||
sessionService.cookieCsrfProtection(req, res, function next(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
sessionMiddleware.cookieCsrfProtection(req);
|
||||
done();
|
||||
});
|
||||
|
||||
it('calls next with BadRequestError if the origin of req does not match the session', function (done) {
|
||||
@ -233,19 +163,12 @@ describe('Session Service', function () {
|
||||
.withArgs('origin').returns('http://host.tld');
|
||||
req.session.origin = 'http://different-host.tld';
|
||||
|
||||
sessionService.cookieCsrfProtection(req, res, function next(err) {
|
||||
try {
|
||||
sessionMiddleware.cookieCsrfProtection(req);
|
||||
} catch (err) {
|
||||
should.equal(err instanceof BadRequestError, true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('safeGetSession', function () {
|
||||
it('is an array of getSession and cookieCsrfProtection', function () {
|
||||
should.deepEqual(sessionService.safeGetSession, [
|
||||
sessionService.getSession,
|
||||
sessionService.cookieCsrfProtection
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user