-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added API Key authentication middleware to v2 API routes #9915
Added API Key authentication middleware to v2 API routes #9915
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! There's a few minor comments and questions 👍
|
||
/** | ||
* Remove 'Bearer' from raw authorization header and extract the JWT token. | ||
* Eg. Authorization: Bearer ${JWT} |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
}; | ||
|
||
const authenticateAdminApiKey = function authenticateAdminApiKey(req, res, next) { | ||
if (req.query && req.query.content_key) { |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
} | ||
|
||
// unknown error | ||
return next(new common.errors.InternalServerError(err)); |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
} = require('../../../lib/common/errors'); | ||
|
||
const authenticateContentApiKey = function authenticateContentApiKey(req, res, next) { | ||
if (req.headers && req.headers.authorization) { |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
@@ -0,0 +1,4 @@ | |||
module.exports = { | |||
admin: require('./admin'), |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
4d3d90f
to
7d5486f
Compare
"description": "Blog Owner" | ||
}, | ||
{ | ||
"name": "Admin API Client", |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
core/server/data/schema/schema.js
Outdated
validations: {isLength: {min: 128, max: 128}} | ||
}, | ||
role_id: {type: 'string', maxlength: 24, nullable: true}, | ||
integration_id: {type: 'string', maxlength: 24, nullable: true}, |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
@@ -0,0 +1,33 @@ | |||
const commands = require('../../../schema').commands; |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
3577149
to
ecca55f
Compare
ecca55f
to
cf519ab
Compare
cf519ab
to
55af833
Compare
4ddbeec
to
cc00d67
Compare
return; | ||
}; | ||
|
||
const rejectAdminApiKey = function rejectAdminApiKey(req, res, next) { |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
35284af
to
2cd5738
Compare
@kirrg001 ready for review |
}, | ||
|
||
// ### v2 API auth middleware | ||
rejectAdminApiKey: apiKeyAuth.admin.rejectAdminApiKey, |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
// ### v2 API auth middleware | ||
rejectAdminApiKey: apiKeyAuth.admin.rejectAdminApiKey, | ||
authenticateAdminApiKey: apiKeyAuth.admin.authenticateAdminApiKey, | ||
rejectContentApiKey: apiKeyAuth.content.rejectContentApiKey, |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
@@ -0,0 +1,212 @@ | |||
const { | |||
authenticateAdminApiKey, | |||
rejectAdminApiKey |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
const common = require('../../../../../server/lib/common'); | ||
const { | ||
authenticateContentApiKey, | ||
rejectContentApiKey |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks solid - just those few things need removing
2cd5738
to
20392e6
Compare
Fixed up the poor global-find-delete job when removing the rejectX middleware 😬 |
:D looks good to me |
@kevinansfield This needs a rebase |
20392e6
to
7e7fc8b
Compare
@@ -100,7 +101,10 @@ const authenticate = { | |||
)(req, res, next); | |||
}, | |||
|
|||
authenticateAdminAPI: [session.safeGetSession, session.getUser] | |||
// ### v2 API auth middleware | |||
authenticateAdminAPI: [session.safeGetSession, session.getUser], |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
@@ -37,7 +37,17 @@ const authorize = { | |||
}; | |||
}, | |||
|
|||
authorizeAdminAPI: [session.ensureUser] | |||
authorizeAdminAPI: [session.ensureUser], |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This now breaks a test - will add a separate commit for that |
refs TryGhost#9865 - add `auth.authenticate.authenticateAdminApiKey` middleware - accepts signed JWT in an `Authorization: Ghost [token]` header - sets `req.api_key` if the token is valid - add `auth.authenticate.authenticateContentApiKey` middleware - accepts `?content_key=` query param, sets `req.api_key` if it's a known Content API key - add `requiresAuthorizedUserOrApiKey` authorization middleware - passes if either `req.user` or `req.api_key` exists - update `authenticatePrivate` middleware stack for v2 admin routes - update `authenticatePublic` middleware stack for v2 content routes
no-issue This can be reimplemented once we have auth helpers for the content API tests.
auth.authenticate.authenticateClient, | ||
auth.authenticate.authenticateUser, | ||
// This is a labs-enabled middleware | ||
auth.authorize.requiresAuthorizedUserPublicAPI, |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
"unknownAdminApiKey": "Unknown Admin API Key", | ||
"unknownContentApiKey": "Unknown Content API Key", | ||
"invalidApiKeyType": "Invalid API Key type", | ||
"invalidJwt": "Invalid JWT", |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
* - the "Audience" claim should match the requested API path | ||
* https://tools.ietf.org/html/rfc7519#section-4.1.3 | ||
*/ | ||
const authenticateAdminApiKey = function authenticateAdminApiKey(req, res, next) { |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
@@ -77,7 +77,8 @@ describe('Public API', function () { | |||
}); | |||
}); | |||
|
|||
it('browse pages', function (done) { | |||
// TODO: move to v2 folder, and don't skip once we have auth helper for content api tests | |||
it.skip('browse pages', function (done) { |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
refs #9865
auth.authenticate.authenticateAdminApiKey
middlewareAuthorization: Ghost [token]
headerreq.api_key
if the token is validauth.authenticate.authenticateContentApiKey
middleware?content_key=
query param, setsreq.api_key
if it's a known Content API keyrequiresAuthorizedUserOrApiKey
authorization middlewarereq.user
orreq.api_key
existsauthenticatePrivate
middleware stack for v2 admin routesauthenticatePublic
middleware stack for v2 content routesSplit out from #9869 for easier review.
TODO:
Bearer
inAuthorization
headerrejectAdminKey
andrejectContentKey
into separate middlewaresauthenticateAdminApiKey
flowauthenticateContentApiKey
middleware to v2 content API routesrejectAdminKey
andrejectContentKey
middleware