0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-11 02:12:21 -05:00

Added JWT authentication for non-versioned API

refs https://github.com/TryGhost/Toolbox/issues/169

- As Ghost prepares to drop API versioning in future major release it the authentication mechanism should take into account non-versioned token audience support. The audience for non-versioned api requests would be limited to "admin" rather than "canary/admin"
This commit is contained in:
Naz 2022-03-03 11:49:44 +07:00 committed by naz
parent 6b730cf201
commit cd1183c9d8
2 changed files with 40 additions and 5 deletions

View file

@ -3,6 +3,7 @@ const url = require('url');
const models = require('../../../models');
const errors = require('@tryghost/errors');
const limitService = require('../../../services/limits');
const config = require('../../../../shared/config');
const tpl = require('@tryghost/tpl');
const _ = require('lodash');
@ -139,12 +140,20 @@ const authenticateWithToken = async (req, res, next, {token, JWT_OPTIONS}) => {
const secret = Buffer.from(apiKey.get('secret'), 'hex');
const {pathname} = url.parse(req.originalUrl);
const [hasMatch, version = 'v4', api = 'admin'] = pathname.match(/ghost\/api\/([^/]+)\/([^/]+)\/(.+)*/); // eslint-disable-line no-unused-vars
const [hasMatch, version, api] = pathname.match(/ghost\/api\/([^/]+)\/([^/]+)\/(.+)*/); // eslint-disable-line no-unused-vars
// ensure the token was meant for this api version
const options = Object.assign({
audience: new RegExp(`\/?${version}\/${api}\/?$`) // eslint-disable-line no-useless-escape
}, JWT_OPTIONS);
// ensure the token was meant for this api
let options;
if (!config.get('api:versions:all').includes(version)) {
// CASE: non-versioned api request
options = Object.assign({
audience: new RegExp(`\/?${version}\/?$`) // eslint-disable-line no-useless-escape
}, JWT_OPTIONS);
} else {
options = Object.assign({
audience: new RegExp(`\/?${version}\/${api}\/?$`) // eslint-disable-line no-useless-escape
}, JWT_OPTIONS);
}
try {
jwt.verify(token, secret, options);

View file

@ -7,6 +7,7 @@ const models = require('../../../../../../core/server/models');
describe('Admin API Key Auth', function () {
const ADMIN_API_URL = '/ghost/api/canary/admin/';
const ADMIN_API_URL_NON_VERSIONED = '/ghost/api/admin/';
before(models.init);
@ -56,6 +57,31 @@ describe('Admin API Key Auth', function () {
});
});
it('should authenticate known+valid non-versioned API key', function (done) {
const token = jwt.sign({
}, this.secret, {
keyid: this.fakeApiKey.id,
algorithm: 'HS256',
expiresIn: '5m',
audience: '/admin/',
issuer: this.fakeApiKey.id
});
const req = {
originalUrl: `${ADMIN_API_URL_NON_VERSIONED}session/`,
headers: {
authorization: `Ghost ${token}`
}
};
const res = {};
apiKeyAuth.admin.authenticate(req, res, (err) => {
should.not.exist(err);
req.api_key.should.eql(this.fakeApiKey);
done();
});
});
it('shouldn\'t authenticate with missing Ghost token', function (done) {
const token = '';
const req = {