mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-30 21:40:39 +03:00
🔥 Removed v0.1 auth services (#11104)
This commit is contained in:
parent
5b59c7b542
commit
95ea5265d5
@ -25,7 +25,6 @@ function initialiseServices() {
|
|||||||
routing.bootstrap.start();
|
routing.bootstrap.start();
|
||||||
|
|
||||||
const permissions = require('./services/permissions'),
|
const permissions = require('./services/permissions'),
|
||||||
auth = require('./services/auth'),
|
|
||||||
apps = require('./services/apps'),
|
apps = require('./services/apps'),
|
||||||
xmlrpc = require('./services/xmlrpc'),
|
xmlrpc = require('./services/xmlrpc'),
|
||||||
slack = require('./services/slack'),
|
slack = require('./services/slack'),
|
||||||
@ -58,9 +57,6 @@ function initialiseServices() {
|
|||||||
require('./analytics-events').init();
|
require('./analytics-events').init();
|
||||||
}
|
}
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
parentApp.use(auth.init());
|
|
||||||
debug('Auth done');
|
|
||||||
|
|
||||||
debug('...`initialiseServices` End');
|
debug('...`initialiseServices` End');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
const models = require('../../models');
|
|
||||||
const common = require('../../lib/common');
|
|
||||||
let strategies;
|
|
||||||
|
|
||||||
strategies = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ClientPasswordStrategy
|
|
||||||
*
|
|
||||||
* This strategy is used to authenticate registered OAuth clients. It is
|
|
||||||
* employed to protect the `token` endpoint, which consumers use to obtain
|
|
||||||
* access tokens. The OAuth 2.0 specification suggests that clients use the
|
|
||||||
* HTTP Basic scheme to authenticate (not implemented yet).
|
|
||||||
* Use of the client password strategy is implemented to support ember-simple-auth.
|
|
||||||
*/
|
|
||||||
clientPasswordStrategy: function clientPasswordStrategy(clientId, clientSecret, done) {
|
|
||||||
return models.Client.findOne({slug: clientId}, {withRelated: ['trustedDomains']})
|
|
||||||
.then(function then(model) {
|
|
||||||
if (model) {
|
|
||||||
var client = model.toJSON({withRelated: ['trustedDomains']});
|
|
||||||
if (client.status === 'enabled' && client.secret === clientSecret) {
|
|
||||||
return done(null, client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return done(null, false);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BearerStrategy
|
|
||||||
*
|
|
||||||
* This strategy is used to authenticate users based on an access token (aka a
|
|
||||||
* bearer token). The user must have previously authorized a client
|
|
||||||
* application, which is issued an access token to make requests on behalf of
|
|
||||||
* the authorizing user.
|
|
||||||
*/
|
|
||||||
bearerStrategy: function bearerStrategy(accessToken, done) {
|
|
||||||
return models.Accesstoken.findOne({token: accessToken})
|
|
||||||
.then(function then(model) {
|
|
||||||
if (model) {
|
|
||||||
var token = model.toJSON();
|
|
||||||
if (token.expires > Date.now()) {
|
|
||||||
return models.User.findOne({id: token.user_id})
|
|
||||||
.then(function then(model) {
|
|
||||||
if (!model) {
|
|
||||||
return done(null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!model.isActive()) {
|
|
||||||
throw new common.errors.NoPermissionError({
|
|
||||||
message: common.i18n.t('errors.models.user.accountSuspended')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = model.toJSON(),
|
|
||||||
info = {scope: '*'};
|
|
||||||
|
|
||||||
return done(null, {id: user.id}, info);
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
return done(err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return done(null, false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return done(null, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = strategies;
|
|
@ -1,107 +1,8 @@
|
|||||||
const passport = require('passport');
|
|
||||||
const authUtils = require('./utils');
|
|
||||||
const models = require('../../models');
|
|
||||||
const common = require('../../lib/common');
|
|
||||||
const session = require('./session');
|
const session = require('./session');
|
||||||
const apiKeyAuth = require('./api-key');
|
const apiKeyAuth = require('./api-key');
|
||||||
const members = require('./members');
|
const members = require('./members');
|
||||||
|
|
||||||
const authenticate = {
|
const authenticate = {
|
||||||
// ### Authenticate Client Middleware
|
|
||||||
authenticateClient: function authenticateClient(req, res, next) {
|
|
||||||
/**
|
|
||||||
* In theory, client authentication is not required for public clients, only for confidential clients.
|
|
||||||
* See e.g. https://tools.ietf.org/html/rfc6749#page-38. Ghost has no differentiation for this at the moment.
|
|
||||||
* See also See https://tools.ietf.org/html/rfc6749#section-2.1.
|
|
||||||
*
|
|
||||||
* Ghost requires client authentication for `grant_type: password`, because we have to ensure that
|
|
||||||
* we tie a client to a new access token. That means `grant_type: refresh_token` does not require
|
|
||||||
* client authentication, because binding a client already happened.
|
|
||||||
*
|
|
||||||
* To sum up:
|
|
||||||
* - password authentication requires client authentication
|
|
||||||
* - refreshing a token does not require client authentication
|
|
||||||
* - public API requires client authentication
|
|
||||||
* - as soon as you send an access token in the header or via query
|
|
||||||
* - we deny public API access
|
|
||||||
* - API access with a Bearer does not require client authentication
|
|
||||||
*/
|
|
||||||
if (authUtils.getBearerAutorizationToken(req) && !authUtils.hasGrantType(req, 'password')) {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.query && req.query.client_id) {
|
|
||||||
req.body.client_id = req.query.client_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.query && req.query.client_secret) {
|
|
||||||
req.body.client_secret = req.query.client_secret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!req.body.client_id || !req.body.client_secret) {
|
|
||||||
return next(new common.errors.UnauthorizedError({
|
|
||||||
message: common.i18n.t('errors.middleware.auth.accessDenied'),
|
|
||||||
context: common.i18n.t('errors.middleware.auth.clientCredentialsNotProvided'),
|
|
||||||
help: common.i18n.t('errors.middleware.auth.forInformationRead', {url: 'https://ghost.org/faq/upgrade-to-ghost-2-0/'})
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return passport.authenticate(['oauth2-client-password'], {session: false, failWithError: false},
|
|
||||||
function authenticate(err, client) {
|
|
||||||
if (err) {
|
|
||||||
return next(err); // will generate a 500 error
|
|
||||||
}
|
|
||||||
|
|
||||||
// req.body needs to be null for GET requests to build options correctly
|
|
||||||
delete req.body.client_id;
|
|
||||||
delete req.body.client_secret;
|
|
||||||
|
|
||||||
if (!client) {
|
|
||||||
return next(new common.errors.UnauthorizedError({
|
|
||||||
message: common.i18n.t('errors.middleware.auth.accessDenied'),
|
|
||||||
context: common.i18n.t('errors.middleware.auth.clientCredentialsNotValid'),
|
|
||||||
help: common.i18n.t('errors.middleware.auth.forInformationRead', {url: 'https://ghost.org/faq/upgrade-to-ghost-2-0/'})
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
req.client = client;
|
|
||||||
|
|
||||||
common.events.emit('client.authenticated', client);
|
|
||||||
return next(null, client);
|
|
||||||
}
|
|
||||||
)(req, res, next);
|
|
||||||
},
|
|
||||||
|
|
||||||
// ### Authenticate User Middleware
|
|
||||||
authenticateUser: function authenticateUser(req, res, next) {
|
|
||||||
return passport.authenticate('bearer', {session: false, failWithError: false},
|
|
||||||
function authenticate(err, user, info) {
|
|
||||||
if (err) {
|
|
||||||
return next(err); // will generate a 500 error
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user) {
|
|
||||||
req.authInfo = info;
|
|
||||||
req.user = user;
|
|
||||||
|
|
||||||
common.events.emit('user.authenticated', user);
|
|
||||||
return next(null, user, info);
|
|
||||||
} else if (authUtils.getBearerAutorizationToken(req)) {
|
|
||||||
return next(new common.errors.UnauthorizedError({
|
|
||||||
message: common.i18n.t('errors.middleware.auth.accessDenied')
|
|
||||||
}));
|
|
||||||
} else if (req.client) {
|
|
||||||
req.user = {id: models.User.externalUser};
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
return next(new common.errors.UnauthorizedError({
|
|
||||||
message: common.i18n.t('errors.middleware.auth.accessDenied')
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
)(req, res, next);
|
|
||||||
},
|
|
||||||
|
|
||||||
authenticateAdminApi: [apiKeyAuth.admin.authenticate, session.authenticate],
|
authenticateAdminApi: [apiKeyAuth.admin.authenticate, session.authenticate],
|
||||||
|
|
||||||
authenticateContentApi: [apiKeyAuth.content.authenticateContentApiKey, members.authenticateMembersToken]
|
authenticateContentApi: [apiKeyAuth.content.authenticateContentApiKey, members.authenticateMembersToken]
|
||||||
|
@ -2,55 +2,6 @@ const labs = require('../labs');
|
|||||||
const common = require('../../lib/common');
|
const common = require('../../lib/common');
|
||||||
|
|
||||||
const authorize = {
|
const authorize = {
|
||||||
// Workaround for missing permissions
|
|
||||||
// TODO: rework when https://github.com/TryGhost/Ghost/issues/3911 is done
|
|
||||||
requiresAuthorizedUser: function requiresAuthorizedUser(req, res, next) {
|
|
||||||
if (req.user && req.user.id) {
|
|
||||||
return next();
|
|
||||||
} else {
|
|
||||||
return next(new common.errors.NoPermissionError({
|
|
||||||
message: common.i18n.t('errors.middleware.auth.pleaseSignIn')
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// ### Require user depending on public API being activated.
|
|
||||||
requiresAuthorizedUserPublicAPI: function requiresAuthorizedUserPublicAPI(req, res, next) {
|
|
||||||
if (labs.isSet('publicAPI') === true) {
|
|
||||||
return next();
|
|
||||||
} else {
|
|
||||||
if (req.user && req.user.id) {
|
|
||||||
return next();
|
|
||||||
} else {
|
|
||||||
// CASE: has no user access and public api is disabled
|
|
||||||
if (labs.isSet('publicAPI') !== true) {
|
|
||||||
return next(new common.errors.NoPermissionError({
|
|
||||||
message: common.i18n.t('errors.middleware.auth.publicAPIDisabled.error'),
|
|
||||||
context: common.i18n.t('errors.middleware.auth.publicAPIDisabled.context'),
|
|
||||||
help: common.i18n.t('errors.middleware.auth.forInformationRead', {url: 'https://ghost.org/docs/api/content/'})
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return next(new common.errors.NoPermissionError({
|
|
||||||
message: common.i18n.t('errors.middleware.auth.pleaseSignIn')
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Requires the authenticated client to match specific client
|
|
||||||
requiresAuthorizedClient: function requiresAuthorizedClient(client) {
|
|
||||||
return function doAuthorizedClient(req, res, next) {
|
|
||||||
if (client && (!req.client || !req.client.name || req.client.name !== client)) {
|
|
||||||
return next(new common.errors.NoPermissionError({
|
|
||||||
message: common.i18n.t('errors.permissions.noPermissionToAction')
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return next();
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
authorizeContentApi(req, res, next) {
|
authorizeContentApi(req, res, next) {
|
||||||
const hasApiKey = req.api_key && req.api_key.id;
|
const hasApiKey = req.api_key && req.api_key.id;
|
||||||
const hasMember = req.member;
|
const hasMember = req.member;
|
||||||
|
@ -17,18 +17,5 @@ module.exports = {
|
|||||||
|
|
||||||
get passwordreset() {
|
get passwordreset() {
|
||||||
return require('./passwordreset');
|
return require('./passwordreset');
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: Get rid of these when v0.1 is gone
|
|
||||||
*/
|
|
||||||
get init() {
|
|
||||||
return (options) => {
|
|
||||||
require('./oauth').init(options);
|
|
||||||
return require('./passport').init(options);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
get oauth() {
|
|
||||||
return require('./oauth');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,195 +0,0 @@
|
|||||||
var oauth2orize = require('oauth2orize'),
|
|
||||||
_ = require('lodash'),
|
|
||||||
passport = require('passport'),
|
|
||||||
models = require('../../models'),
|
|
||||||
authUtils = require('./utils'),
|
|
||||||
web = require('../../web'),
|
|
||||||
common = require('../../lib/common'),
|
|
||||||
oauthServer,
|
|
||||||
oauth;
|
|
||||||
|
|
||||||
function exchangeRefreshToken(client, refreshToken, scope, body, authInfo, done) {
|
|
||||||
models.Base.transaction(function (transacting) {
|
|
||||||
var options = {
|
|
||||||
transacting: transacting
|
|
||||||
};
|
|
||||||
|
|
||||||
return models.Refreshtoken.findOne({token: refreshToken}, _.merge({forUpdate: true}, options))
|
|
||||||
.then(function then(model) {
|
|
||||||
if (!model) {
|
|
||||||
throw new common.errors.NoPermissionError({
|
|
||||||
message: common.i18n.t('errors.middleware.oauth.invalidRefreshToken')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var token = model.toJSON();
|
|
||||||
|
|
||||||
if (token.expires <= Date.now()) {
|
|
||||||
throw new common.errors.UnauthorizedError({
|
|
||||||
message: common.i18n.t('errors.middleware.oauth.refreshTokenExpired')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// @TODO: this runs outside of the transaction
|
|
||||||
web.shared.middlewares.api.spamPrevention.userLogin()
|
|
||||||
.reset(authInfo.ip, body.refresh_token + 'login');
|
|
||||||
|
|
||||||
return authUtils.createTokens({
|
|
||||||
clientId: token.client_id,
|
|
||||||
userId: token.user_id,
|
|
||||||
oldAccessToken: authInfo.accessToken,
|
|
||||||
oldRefreshToken: refreshToken,
|
|
||||||
oldRefreshId: token.id
|
|
||||||
}, options).then(function (response) {
|
|
||||||
return {
|
|
||||||
access_token: response.access_token,
|
|
||||||
expires_in: response.expires_in
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}).then(function (response) {
|
|
||||||
done(null, response.access_token, {expires_in: response.expires_in});
|
|
||||||
}).catch(function (err) {
|
|
||||||
if (common.errors.utils.isIgnitionError(err)) {
|
|
||||||
return done(err, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
done(new common.errors.InternalServerError({
|
|
||||||
err: err
|
|
||||||
}), false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are required to pass in authInfo in order to reset spam counter for user login
|
|
||||||
function exchangePassword(client, username, password, scope, body, authInfo, done) {
|
|
||||||
if (!client || !client.id) {
|
|
||||||
return done(new common.errors.UnauthorizedError({
|
|
||||||
message: common.i18n.t('errors.middleware.auth.clientCredentialsNotProvided')
|
|
||||||
}), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate the user
|
|
||||||
return models.User.check({email: username, password: password})
|
|
||||||
.then(function then(user) {
|
|
||||||
return authUtils.createTokens({
|
|
||||||
clientId: client.id,
|
|
||||||
userId: user.id
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(function then(response) {
|
|
||||||
web.shared.middlewares.api.spamPrevention.userLogin()
|
|
||||||
.reset(authInfo.ip, username + 'login');
|
|
||||||
|
|
||||||
return done(null, response.access_token, response.refresh_token, {expires_in: response.expires_in});
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
done(err, false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function exchangeAuthorizationCode(req, res, next) {
|
|
||||||
if (!req.body.authorizationCode) {
|
|
||||||
return next(new common.errors.UnauthorizedError({
|
|
||||||
message: common.i18n.t('errors.middleware.auth.accessDenied')
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
req.query.code = req.body.authorizationCode;
|
|
||||||
|
|
||||||
passport.authenticate('ghost', {session: false, failWithError: false}, function authenticate(err, user) {
|
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return next(new common.errors.UnauthorizedError({
|
|
||||||
message: common.i18n.t('errors.middleware.auth.accessDenied')
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
web.shared.middlewares.api.spamPrevention.userLogin()
|
|
||||||
.reset(req.authInfo.ip, req.body.authorizationCode + 'login');
|
|
||||||
|
|
||||||
authUtils.createTokens({
|
|
||||||
clientId: req.client.id,
|
|
||||||
userId: user.id
|
|
||||||
}).then(function then(response) {
|
|
||||||
res.json({
|
|
||||||
access_token: response.access_token,
|
|
||||||
refresh_token: response.refresh_token,
|
|
||||||
expires_in: response.expires_in
|
|
||||||
});
|
|
||||||
}).catch(function (err) {
|
|
||||||
next(err);
|
|
||||||
});
|
|
||||||
})(req, res, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
oauth = {
|
|
||||||
|
|
||||||
init: function init() {
|
|
||||||
oauthServer = oauth2orize.createServer();
|
|
||||||
// remove all expired accesstokens on startup
|
|
||||||
models.Accesstoken.destroyAllExpired();
|
|
||||||
|
|
||||||
// remove all expired refreshtokens on startup
|
|
||||||
models.Refreshtoken.destroyAllExpired();
|
|
||||||
|
|
||||||
// Exchange user id and password for access tokens. The callback accepts the
|
|
||||||
// `client`, which is exchanging the user's name and password from the
|
|
||||||
// authorization request for verification. If these values are validated, the
|
|
||||||
// application issues an access token on behalf of the user who authorized the code.
|
|
||||||
oauthServer.exchange(oauth2orize.exchange.password({userProperty: 'client'},
|
|
||||||
exchangePassword));
|
|
||||||
|
|
||||||
// Exchange the refresh token to obtain an access token. The callback accepts the
|
|
||||||
// `client`, which is exchanging a `refreshToken` previously issued by the server
|
|
||||||
// for verification. If these values are validated, the application issues an
|
|
||||||
// access token on behalf of the user who authorized the code.
|
|
||||||
oauthServer.exchange(oauth2orize.exchange.refreshToken({userProperty: 'client'},
|
|
||||||
exchangeRefreshToken));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exchange authorization_code for an access token.
|
|
||||||
* We forward to authorization code to Ghost.org.
|
|
||||||
*
|
|
||||||
* oauth2orize offers a default implementation via exchange.authorizationCode, but this function
|
|
||||||
* wraps the express request and response. So no chance to get access to it.
|
|
||||||
* We use passport to communicate with Ghost.org. Passport's module design requires the express req/res.
|
|
||||||
*
|
|
||||||
* For now it's OK to not use exchange.authorizationCode. You can read through the implementation here:
|
|
||||||
* https://github.com/jaredhanson/oauth2orize/blob/master/lib/exchange/authorizationCode.js
|
|
||||||
* As you can see, it does some validation and set's some headers, not very very important,
|
|
||||||
* but it's part of the oauth2 spec.
|
|
||||||
*
|
|
||||||
* @TODO: How to use exchange.authorizationCode in combination of passport?
|
|
||||||
*/
|
|
||||||
oauthServer.exchange('authorization_code', exchangeAuthorizationCode);
|
|
||||||
},
|
|
||||||
|
|
||||||
// ### Generate access token Middleware
|
|
||||||
// register the oauth2orize middleware for password and refresh token grants
|
|
||||||
generateAccessToken: function generateAccessToken(req, res, next) {
|
|
||||||
/**
|
|
||||||
* TODO:
|
|
||||||
* https://github.com/jaredhanson/oauth2orize/issues/182
|
|
||||||
* oauth2orize only offers the option to forward request information via authInfo object
|
|
||||||
*
|
|
||||||
* Important: only used for resetting the brute count (access to req.ip)
|
|
||||||
*/
|
|
||||||
req.authInfo = {
|
|
||||||
ip: req.ip,
|
|
||||||
accessToken: authUtils.getBearerAutorizationToken(req)
|
|
||||||
};
|
|
||||||
|
|
||||||
return oauthServer.token()(req, res, function (err) {
|
|
||||||
if (err && err.status === 400) {
|
|
||||||
err = new common.errors.BadRequestError({err: err, message: err.message});
|
|
||||||
}
|
|
||||||
|
|
||||||
next(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = oauth;
|
|
@ -1,15 +0,0 @@
|
|||||||
var ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy,
|
|
||||||
BearerStrategy = require('passport-http-bearer').Strategy,
|
|
||||||
passport = require('passport'),
|
|
||||||
authStrategies = require('./auth-strategies');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* auth types:
|
|
||||||
* - password: local login
|
|
||||||
*/
|
|
||||||
exports.init = function initPassport() {
|
|
||||||
passport.use(new ClientPasswordStrategy(authStrategies.clientPasswordStrategy));
|
|
||||||
passport.use(new BearerStrategy(authStrategies.bearerStrategy));
|
|
||||||
|
|
||||||
return passport.initialize();
|
|
||||||
};
|
|
@ -1,137 +0,0 @@
|
|||||||
var Promise = require('bluebird'),
|
|
||||||
_ = require('lodash'),
|
|
||||||
debug = require('ghost-ignition').debug('auth:utils'),
|
|
||||||
models = require('../../models'),
|
|
||||||
security = require('../../lib/security'),
|
|
||||||
constants = require('../../lib/constants'),
|
|
||||||
_private = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The initial idea was to delete all old tokens connected to a user and a client.
|
|
||||||
* But if multiple browsers/apps are using the same client, we would log out them out.
|
|
||||||
* So the idea is to always decrease the expiry of the old access token if available.
|
|
||||||
* This access token auto expires and get's cleaned up on bootstrap (see oauth.js).
|
|
||||||
*/
|
|
||||||
_private.decreaseOldAccessTokenExpiry = function decreaseOldAccessTokenExpiry(data, options) {
|
|
||||||
debug('decreaseOldAccessTokenExpiry', data);
|
|
||||||
|
|
||||||
if (!data.token) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
return models.Accesstoken.findOne(data, options)
|
|
||||||
.then(function (oldAccessToken) {
|
|
||||||
if (!oldAccessToken) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
return models.Accesstoken.edit({
|
|
||||||
expires: Date.now() + constants.FIVE_MINUTES_MS
|
|
||||||
}, _.merge({id: oldAccessToken.id}, options));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
_private.handleOldRefreshToken = function handleOldRefreshToken(data, options) {
|
|
||||||
debug('handleOldRefreshToken', data.oldRefreshToken);
|
|
||||||
|
|
||||||
if (!data.oldRefreshToken) {
|
|
||||||
return models.Refreshtoken.add({
|
|
||||||
token: data.newRefreshToken,
|
|
||||||
user_id: data.userId,
|
|
||||||
client_id: data.clientId,
|
|
||||||
expires: data.refreshExpires
|
|
||||||
}, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
// extend refresh token expiry
|
|
||||||
return models.Refreshtoken.edit({
|
|
||||||
expires: data.refreshExpires
|
|
||||||
}, _.merge({id: data.oldRefreshId}, options));
|
|
||||||
};
|
|
||||||
|
|
||||||
_private.handleTokenCreation = function handleTokenCreation(data, options) {
|
|
||||||
var oldAccessToken = data.oldAccessToken,
|
|
||||||
oldRefreshToken = data.oldRefreshToken,
|
|
||||||
oldRefreshId = data.oldRefreshId,
|
|
||||||
newAccessToken = security.identifier.uid(191),
|
|
||||||
newRefreshToken = security.identifier.uid(191),
|
|
||||||
accessExpires = Date.now() + constants.ONE_MONTH_MS,
|
|
||||||
refreshExpires = Date.now() + constants.SIX_MONTH_MS,
|
|
||||||
clientId = data.clientId,
|
|
||||||
userId = data.userId;
|
|
||||||
|
|
||||||
return _private.decreaseOldAccessTokenExpiry({token: oldAccessToken}, options)
|
|
||||||
.then(function () {
|
|
||||||
return _private.handleOldRefreshToken({
|
|
||||||
userId: userId,
|
|
||||||
clientId: clientId,
|
|
||||||
oldRefreshToken: oldRefreshToken,
|
|
||||||
oldRefreshId: oldRefreshId,
|
|
||||||
newRefreshToken: newRefreshToken,
|
|
||||||
refreshExpires: refreshExpires
|
|
||||||
}, options);
|
|
||||||
})
|
|
||||||
.then(function (refreshToken) {
|
|
||||||
return models.Accesstoken.add({
|
|
||||||
token: newAccessToken,
|
|
||||||
user_id: userId,
|
|
||||||
client_id: clientId,
|
|
||||||
issued_by: refreshToken.id,
|
|
||||||
expires: accessExpires
|
|
||||||
}, options);
|
|
||||||
})
|
|
||||||
.then(function () {
|
|
||||||
return {
|
|
||||||
access_token: newAccessToken,
|
|
||||||
refresh_token: newRefreshToken,
|
|
||||||
expires_in: constants.ONE_MONTH_S
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A user can have one token per client at a time.
|
|
||||||
* If the user requests a new pair of tokens, we decrease the expiry of the old access token
|
|
||||||
* and re-add the refresh token (this happens because this function is used for 3 different cases).
|
|
||||||
* If the operation fails in between, the user can still use e.g. the refresh token and try again.
|
|
||||||
*/
|
|
||||||
module.exports.createTokens = function createTokens(data, modelOptions) {
|
|
||||||
data = data || {};
|
|
||||||
modelOptions = modelOptions || {};
|
|
||||||
|
|
||||||
debug('createTokens');
|
|
||||||
|
|
||||||
if (modelOptions.transacting) {
|
|
||||||
return _private.handleTokenCreation(data, modelOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return models.Base.transaction(function (transaction) {
|
|
||||||
modelOptions.transacting = transaction;
|
|
||||||
|
|
||||||
return _private.handleTokenCreation(data, modelOptions);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.getBearerAutorizationToken = function (req) {
|
|
||||||
var parts,
|
|
||||||
scheme,
|
|
||||||
token;
|
|
||||||
|
|
||||||
if (req.headers && req.headers.authorization) {
|
|
||||||
parts = req.headers.authorization.split(' ');
|
|
||||||
scheme = parts[0];
|
|
||||||
|
|
||||||
if (/^Bearer$/i.test(scheme)) {
|
|
||||||
token = parts[1];
|
|
||||||
}
|
|
||||||
} else if (req.query && req.query.access_token) {
|
|
||||||
token = req.query.access_token;
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.hasGrantType = function hasGrantType(req, type) {
|
|
||||||
return req.body && Object.prototype.hasOwnProperty.call(req.body, 'grant_type') && req.body.grant_type === type
|
|
||||||
|| req.query && Object.prototype.hasOwnProperty.call(req.query, 'grant_type') && req.query.grant_type === type;
|
|
||||||
};
|
|
@ -1,226 +0,0 @@
|
|||||||
var should = require('should'),
|
|
||||||
sinon = require('sinon'),
|
|
||||||
Promise = require('bluebird'),
|
|
||||||
_ = require('lodash'),
|
|
||||||
|
|
||||||
authStrategies = require('../../../../server/services/auth/auth-strategies'),
|
|
||||||
Models = require('../../../../server/models'),
|
|
||||||
common = require('../../../../server/lib/common'),
|
|
||||||
security = require('../../../../server/lib/security'),
|
|
||||||
constants = require('../../../../server/lib/constants'),
|
|
||||||
|
|
||||||
fakeClient = {
|
|
||||||
slug: 'ghost-admin',
|
|
||||||
secret: 'not_available',
|
|
||||||
status: 'enabled'
|
|
||||||
},
|
|
||||||
|
|
||||||
fakeValidToken = {
|
|
||||||
user_id: 3,
|
|
||||||
token: 'valid-token',
|
|
||||||
client_id: 1,
|
|
||||||
expires: Date.now() + constants.ONE_DAY_MS
|
|
||||||
},
|
|
||||||
fakeInvalidToken = {
|
|
||||||
user_id: 3,
|
|
||||||
token: 'expired-token',
|
|
||||||
client_id: 1,
|
|
||||||
expires: Date.now() - constants.ONE_DAY_MS
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Auth Strategies', function () {
|
|
||||||
var next;
|
|
||||||
|
|
||||||
before(function () {
|
|
||||||
// Loads all the models
|
|
||||||
Models.init();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
next = sinon.spy();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
sinon.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Client Password Strategy', function () {
|
|
||||||
var clientStub;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
clientStub = sinon.stub(Models.Client, 'findOne');
|
|
||||||
clientStub.returns(new Promise.resolve());
|
|
||||||
clientStub.withArgs({slug: fakeClient.slug}).returns(new Promise.resolve({
|
|
||||||
toJSON: function () {
|
|
||||||
return fakeClient;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should find client', function (done) {
|
|
||||||
var clientId = 'ghost-admin',
|
|
||||||
clientSecret = 'not_available';
|
|
||||||
|
|
||||||
authStrategies.clientPasswordStrategy(clientId, clientSecret, next).then(function () {
|
|
||||||
clientStub.calledOnce.should.be.true();
|
|
||||||
clientStub.calledWith({slug: clientId}).should.be.true();
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.firstCall.args.length.should.eql(2);
|
|
||||||
should.equal(next.firstCall.args[0], null);
|
|
||||||
next.firstCall.args[1].slug.should.eql(clientId);
|
|
||||||
done();
|
|
||||||
}).catch(done);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t find client with invalid id', function (done) {
|
|
||||||
var clientId = 'invalid_id',
|
|
||||||
clientSecret = 'not_available';
|
|
||||||
authStrategies.clientPasswordStrategy(clientId, clientSecret, next).then(function () {
|
|
||||||
clientStub.calledOnce.should.be.true();
|
|
||||||
clientStub.calledWith({slug: clientId}).should.be.true();
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith(null, false).should.be.true();
|
|
||||||
done();
|
|
||||||
}).catch(done);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t find client with invalid secret', function (done) {
|
|
||||||
var clientId = 'ghost-admin',
|
|
||||||
clientSecret = 'invalid_secret';
|
|
||||||
authStrategies.clientPasswordStrategy(clientId, clientSecret, next).then(function () {
|
|
||||||
clientStub.calledOnce.should.be.true();
|
|
||||||
clientStub.calledWith({slug: clientId}).should.be.true();
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith(null, false).should.be.true();
|
|
||||||
done();
|
|
||||||
}).catch(done);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t auth client that is disabled', function (done) {
|
|
||||||
var clientId = 'ghost-admin',
|
|
||||||
clientSecret = 'not_available';
|
|
||||||
|
|
||||||
fakeClient.status = 'disabled';
|
|
||||||
|
|
||||||
authStrategies.clientPasswordStrategy(clientId, clientSecret, next).then(function () {
|
|
||||||
clientStub.calledOnce.should.be.true();
|
|
||||||
clientStub.calledWith({slug: clientId}).should.be.true();
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith(null, false).should.be.true();
|
|
||||||
done();
|
|
||||||
}).catch(done);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Bearer Strategy', function () {
|
|
||||||
var tokenStub, userStub, userIsActive;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
tokenStub = sinon.stub(Models.Accesstoken, 'findOne');
|
|
||||||
tokenStub.returns(new Promise.resolve());
|
|
||||||
tokenStub.withArgs({token: fakeValidToken.token}).returns(new Promise.resolve({
|
|
||||||
toJSON: function () {
|
|
||||||
return fakeValidToken;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
tokenStub.withArgs({token: fakeInvalidToken.token}).returns(new Promise.resolve({
|
|
||||||
toJSON: function () {
|
|
||||||
return fakeInvalidToken;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
userStub = sinon.stub(Models.User, 'findOne');
|
|
||||||
userStub.returns(new Promise.resolve());
|
|
||||||
userStub.withArgs({id: 3}).returns(new Promise.resolve({
|
|
||||||
toJSON: function () {
|
|
||||||
return {id: 3};
|
|
||||||
},
|
|
||||||
isActive: function () {
|
|
||||||
return userIsActive;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should find user with valid token', function (done) {
|
|
||||||
var accessToken = 'valid-token',
|
|
||||||
userId = 3;
|
|
||||||
|
|
||||||
userIsActive = true;
|
|
||||||
|
|
||||||
authStrategies.bearerStrategy(accessToken, next).then(function () {
|
|
||||||
tokenStub.calledOnce.should.be.true();
|
|
||||||
tokenStub.calledWith({token: accessToken}).should.be.true();
|
|
||||||
userStub.calledOnce.should.be.true();
|
|
||||||
userStub.calledWith({id: userId}).should.be.true();
|
|
||||||
next.calledOnce.should.be.true();
|
|
||||||
next.firstCall.args.length.should.eql(3);
|
|
||||||
next.calledWith(null, {id: userId}, {scope: '*'}).should.be.true();
|
|
||||||
done();
|
|
||||||
}).catch(done);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should find user with valid token, but user is suspended', function (done) {
|
|
||||||
var accessToken = 'valid-token',
|
|
||||||
userId = 3;
|
|
||||||
|
|
||||||
userIsActive = false;
|
|
||||||
|
|
||||||
authStrategies.bearerStrategy(accessToken, next).then(function () {
|
|
||||||
tokenStub.calledOnce.should.be.true();
|
|
||||||
tokenStub.calledWith({token: accessToken}).should.be.true();
|
|
||||||
userStub.calledOnce.should.be.true();
|
|
||||||
userStub.calledWith({id: userId}).should.be.true();
|
|
||||||
next.calledOnce.should.be.true();
|
|
||||||
next.firstCall.args.length.should.eql(1);
|
|
||||||
(next.firstCall.args[0] instanceof common.errors.NoPermissionError).should.eql(true);
|
|
||||||
next.firstCall.args[0].message.should.eql('Your account was suspended.');
|
|
||||||
done();
|
|
||||||
}).catch(done);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t find user with invalid token', function (done) {
|
|
||||||
var accessToken = 'invalid_token';
|
|
||||||
|
|
||||||
authStrategies.bearerStrategy(accessToken, next).then(function () {
|
|
||||||
tokenStub.calledOnce.should.be.true();
|
|
||||||
tokenStub.calledWith({token: accessToken}).should.be.true();
|
|
||||||
userStub.called.should.be.false();
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith(null, false).should.be.true();
|
|
||||||
done();
|
|
||||||
}).catch(done);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should find user that doesn\'t exist', function (done) {
|
|
||||||
var accessToken = 'valid-token',
|
|
||||||
userId = 2;
|
|
||||||
|
|
||||||
// override user
|
|
||||||
fakeValidToken.user_id = userId;
|
|
||||||
|
|
||||||
authStrategies.bearerStrategy(accessToken, next).then(function () {
|
|
||||||
tokenStub.calledOnce.should.be.true();
|
|
||||||
tokenStub.calledWith({token: accessToken}).should.be.true();
|
|
||||||
userStub.calledOnce.should.be.true();
|
|
||||||
userStub.calledWith({id: userId}).should.be.true();
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith(null, false).should.be.true();
|
|
||||||
done();
|
|
||||||
}).catch(done);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should find user with expired token', function (done) {
|
|
||||||
var accessToken = 'expired-token';
|
|
||||||
|
|
||||||
authStrategies.bearerStrategy(accessToken, next).then(function () {
|
|
||||||
tokenStub.calledOnce.should.be.true();
|
|
||||||
tokenStub.calledWith({token: accessToken}).should.be.true();
|
|
||||||
userStub.calledOnce.should.be.false();
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith(null, false).should.be.true();
|
|
||||||
done();
|
|
||||||
}).catch(done);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,366 +0,0 @@
|
|||||||
const should = require('should');
|
|
||||||
const sinon = require('sinon');
|
|
||||||
const passport = require('passport');
|
|
||||||
const BearerStrategy = require('passport-http-bearer').Strategy;
|
|
||||||
const ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy;
|
|
||||||
const auth = require('../../../../server/services/auth');
|
|
||||||
const common = require('../../../../server/lib/common');
|
|
||||||
const models = require('../../../../server/models');
|
|
||||||
const labs = require('../../../../server/services/labs');
|
|
||||||
const user = {id: 1};
|
|
||||||
const info = {scope: '*'};
|
|
||||||
const token = 'test_token';
|
|
||||||
const testClient = 'test_client';
|
|
||||||
const testSecret = 'not_available';
|
|
||||||
const client = {
|
|
||||||
id: 2,
|
|
||||||
type: 'ua'
|
|
||||||
};
|
|
||||||
|
|
||||||
function registerSuccessfulBearerStrategy() {
|
|
||||||
// register fake BearerStrategy which always authenticates
|
|
||||||
passport.use(new BearerStrategy(
|
|
||||||
function strategy(accessToken, done) {
|
|
||||||
accessToken.should.eql(token);
|
|
||||||
return done(null, user, info);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerUnsuccessfulBearerStrategy() {
|
|
||||||
// register fake BearerStrategy which always authenticates
|
|
||||||
passport.use(new BearerStrategy(
|
|
||||||
function strategy(accessToken, done) {
|
|
||||||
accessToken.should.eql(token);
|
|
||||||
return done(null, false);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerFaultyBearerStrategy() {
|
|
||||||
// register fake BearerStrategy which always authenticates
|
|
||||||
passport.use(new BearerStrategy(
|
|
||||||
function strategy(accessToken, done) {
|
|
||||||
accessToken.should.eql(token);
|
|
||||||
return done('error');
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerSuccessfulClientPasswordStrategy() {
|
|
||||||
// register fake BearerStrategy which always authenticates
|
|
||||||
passport.use(new ClientPasswordStrategy(
|
|
||||||
function strategy(clientId, clientSecret, done) {
|
|
||||||
clientId.should.eql(testClient);
|
|
||||||
clientSecret.should.eql('not_available');
|
|
||||||
return done(null, client);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerUnsuccessfulClientPasswordStrategy() {
|
|
||||||
// register fake BearerStrategy which always authenticates
|
|
||||||
passport.use(new ClientPasswordStrategy(
|
|
||||||
function strategy(clientId, clientSecret, done) {
|
|
||||||
clientId.should.eql(testClient);
|
|
||||||
clientSecret.should.eql('not_available');
|
|
||||||
return done(null, false);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerFaultyClientPasswordStrategy() {
|
|
||||||
// register fake BearerStrategy which always authenticates
|
|
||||||
passport.use(new ClientPasswordStrategy(
|
|
||||||
function strategy(clientId, clientSecret, done) {
|
|
||||||
clientId.should.eql(testClient);
|
|
||||||
clientSecret.should.eql('not_available');
|
|
||||||
return done('error');
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Auth', function () {
|
|
||||||
var res, req, next, loggingStub;
|
|
||||||
|
|
||||||
before(function () {
|
|
||||||
models.init();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
req = {};
|
|
||||||
res = {};
|
|
||||||
next = sinon.spy();
|
|
||||||
loggingStub = sinon.stub(common.logging, 'error');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
sinon.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should require authorized user (user exists)', function (done) {
|
|
||||||
req.user = {id: 1};
|
|
||||||
|
|
||||||
auth.authorize.requiresAuthorizedUser(req, res, next);
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith().should.be.true();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should require authorized user (user is missing)', function (done) {
|
|
||||||
req.user = false;
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
var next = function next(err) {
|
|
||||||
err.statusCode.should.eql(403);
|
|
||||||
(err instanceof common.errors.NoPermissionError).should.eql(true);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
auth.authorize.requiresAuthorizedUser(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('User Authentication', function () {
|
|
||||||
it('should authenticate user', function (done) {
|
|
||||||
req.headers = {};
|
|
||||||
req.headers.authorization = 'Bearer ' + token;
|
|
||||||
|
|
||||||
registerSuccessfulBearerStrategy();
|
|
||||||
auth.authenticate.authenticateUser(req, res, next);
|
|
||||||
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith(null, user, info).should.be.true();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t pass with client, no bearer token', function (done) {
|
|
||||||
req.headers = {};
|
|
||||||
req.client = {id: 1};
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
auth.authenticate.authenticateUser(req, res, next);
|
|
||||||
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith().should.be.true();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t authenticate user', function (done) {
|
|
||||||
req.headers = {};
|
|
||||||
req.headers.authorization = 'Bearer ' + token;
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
var next = function next(err) {
|
|
||||||
err.statusCode.should.eql(401);
|
|
||||||
(err instanceof common.errors.UnauthorizedError).should.eql(true);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
registerUnsuccessfulBearerStrategy();
|
|
||||||
auth.authenticate.authenticateUser(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t authenticate without bearer token', function (done) {
|
|
||||||
req.headers = {};
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
var next = function next(err) {
|
|
||||||
err.statusCode.should.eql(401);
|
|
||||||
(err instanceof common.errors.UnauthorizedError).should.eql(true);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
registerUnsuccessfulBearerStrategy();
|
|
||||||
auth.authenticate.authenticateUser(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t authenticate with bearer token and client', function (done) {
|
|
||||||
req.headers = {};
|
|
||||||
req.headers.authorization = 'Bearer ' + token;
|
|
||||||
req.client = {id: 1};
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
var next = function next(err) {
|
|
||||||
err.statusCode.should.eql(401);
|
|
||||||
(err instanceof common.errors.UnauthorizedError).should.eql(true);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
registerUnsuccessfulBearerStrategy();
|
|
||||||
auth.authenticate.authenticateUser(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t authenticate when error', function (done) {
|
|
||||||
req.headers = {};
|
|
||||||
req.headers.authorization = 'Bearer ' + token;
|
|
||||||
|
|
||||||
registerFaultyBearerStrategy();
|
|
||||||
auth.authenticate.authenticateUser(req, res, next);
|
|
||||||
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith('error').should.be.true();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Client Authentication', function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
sinon.stub(labs, 'isSet').withArgs('publicAPI').returns(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t require authorized client with bearer token', function (done) {
|
|
||||||
req.headers = {};
|
|
||||||
req.headers.authorization = 'Bearer ' + token;
|
|
||||||
|
|
||||||
auth.authenticate.authenticateClient(req, res, next);
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith().should.be.true();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t authenticate client with broken bearer token', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.headers = {};
|
|
||||||
req.headers.authorization = 'Bearer';
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
var next = function next(err) {
|
|
||||||
err.statusCode.should.eql(401);
|
|
||||||
(err instanceof common.errors.UnauthorizedError).should.eql(true);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
auth.authenticate.authenticateClient(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t authenticate client without client_id/client_secret', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
var next = function next(err) {
|
|
||||||
err.statusCode.should.eql(401);
|
|
||||||
(err instanceof common.errors.UnauthorizedError).should.eql(true);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
auth.authenticate.authenticateClient(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t authenticate client without client_id', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.body.client_secret = testSecret;
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
var next = function next(err) {
|
|
||||||
err.statusCode.should.eql(401);
|
|
||||||
(err instanceof common.errors.UnauthorizedError).should.eql(true);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
auth.authenticate.authenticateClient(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t authenticate client without client_secret', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.body.client_id = testClient;
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
var next = function next(err) {
|
|
||||||
err.statusCode.should.eql(401);
|
|
||||||
(err instanceof common.errors.UnauthorizedError).should.eql(true);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
auth.authenticate.authenticateClient(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t authenticate without full client credentials', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.body.client_id = testClient;
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
var next = function next(err) {
|
|
||||||
err.statusCode.should.eql(401);
|
|
||||||
(err instanceof common.errors.UnauthorizedError).should.eql(true);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
registerUnsuccessfulClientPasswordStrategy();
|
|
||||||
auth.authenticate.authenticateClient(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t authenticate invalid/unknown client', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.body.client_id = testClient;
|
|
||||||
req.body.client_secret = testSecret;
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
var next = function next(err) {
|
|
||||||
err.statusCode.should.eql(401);
|
|
||||||
(err instanceof common.errors.UnauthorizedError).should.eql(true);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
registerUnsuccessfulClientPasswordStrategy();
|
|
||||||
auth.authenticate.authenticateClient(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should authenticate valid/known client', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.body.client_id = testClient;
|
|
||||||
req.body.client_secret = testSecret;
|
|
||||||
req.headers = {};
|
|
||||||
|
|
||||||
registerSuccessfulClientPasswordStrategy();
|
|
||||||
auth.authenticate.authenticateClient(req, res, next);
|
|
||||||
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith(null, client).should.be.true();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should authenticate client with id in query', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.query = {};
|
|
||||||
req.query.client_id = testClient;
|
|
||||||
req.query.client_secret = testSecret;
|
|
||||||
req.headers = {};
|
|
||||||
|
|
||||||
registerSuccessfulClientPasswordStrategy();
|
|
||||||
auth.authenticate.authenticateClient(req, res, next);
|
|
||||||
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith(null, client).should.be.true();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should authenticate client with id + secret in query', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.query = {};
|
|
||||||
req.query.client_id = testClient;
|
|
||||||
req.query.client_secret = testSecret;
|
|
||||||
req.headers = {};
|
|
||||||
|
|
||||||
registerSuccessfulClientPasswordStrategy();
|
|
||||||
auth.authenticate.authenticateClient(req, res, next);
|
|
||||||
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith(null, client).should.be.true();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t authenticate when error', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.body.client_id = testClient;
|
|
||||||
req.body.client_secret = testSecret;
|
|
||||||
res.status = {};
|
|
||||||
|
|
||||||
registerFaultyClientPasswordStrategy();
|
|
||||||
auth.authenticate.authenticateClient(req, res, next);
|
|
||||||
|
|
||||||
next.called.should.be.true();
|
|
||||||
next.calledWith('error').should.be.true();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,406 +0,0 @@
|
|||||||
var should = require('should'),
|
|
||||||
sinon = require('sinon'),
|
|
||||||
Promise = require('bluebird'),
|
|
||||||
passport = require('passport'),
|
|
||||||
testUtils = require('../../../utils'),
|
|
||||||
oAuth = require('../../../../server/services/auth/oauth'),
|
|
||||||
authUtils = require('../../../../server/services/auth/utils'),
|
|
||||||
spamPrevention = require('../../../../server/web/shared/middlewares/api/spam-prevention'),
|
|
||||||
common = require('../../../../server/lib/common'),
|
|
||||||
models = require('../../../../server/models');
|
|
||||||
|
|
||||||
describe('OAuth', function () {
|
|
||||||
var next, req, res;
|
|
||||||
|
|
||||||
before(function () {
|
|
||||||
models.init();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
req = {};
|
|
||||||
res = {};
|
|
||||||
next = sinon.spy();
|
|
||||||
|
|
||||||
sinon.stub(spamPrevention.userLogin(), 'reset');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
sinon.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Generate Token from Password', function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
sinon.stub(models.Accesstoken, 'destroyAllExpired')
|
|
||||||
.returns(new Promise.resolve());
|
|
||||||
sinon.stub(models.Refreshtoken, 'destroyAllExpired')
|
|
||||||
.returns(new Promise.resolve());
|
|
||||||
oAuth.init();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Successfully generate access token.', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.client = {
|
|
||||||
slug: 'test'
|
|
||||||
};
|
|
||||||
req.connection = {remoteAddress: '127.0.0.1'};
|
|
||||||
req.authInfo = {ip: '127.0.0.1'};
|
|
||||||
|
|
||||||
req.body.grant_type = 'password';
|
|
||||||
req.body.username = 'username';
|
|
||||||
req.body.password = 'password';
|
|
||||||
req.client = {
|
|
||||||
id: 1
|
|
||||||
};
|
|
||||||
|
|
||||||
res.setHeader = function () {
|
|
||||||
};
|
|
||||||
res.end = function () {
|
|
||||||
};
|
|
||||||
|
|
||||||
sinon.stub(models.User, 'check')
|
|
||||||
.withArgs({email: 'username', password: 'password'}).returns(Promise.resolve({
|
|
||||||
id: 1
|
|
||||||
}));
|
|
||||||
|
|
||||||
sinon.stub(authUtils, 'createTokens')
|
|
||||||
.returns(Promise.resolve({
|
|
||||||
access_token: 'AT',
|
|
||||||
refresh_token: 'RT',
|
|
||||||
expires_in: Date.now() + 1000
|
|
||||||
}));
|
|
||||||
|
|
||||||
sinon.stub(res, 'setHeader').callsFake(function () {
|
|
||||||
});
|
|
||||||
|
|
||||||
sinon.stub(res, 'end').callsFake(function (json) {
|
|
||||||
try {
|
|
||||||
should.exist(json);
|
|
||||||
json = JSON.parse(json);
|
|
||||||
json.should.have.property('access_token');
|
|
||||||
json.should.have.property('refresh_token');
|
|
||||||
json.should.have.property('expires_in');
|
|
||||||
json.should.have.property('token_type', 'Bearer');
|
|
||||||
next.called.should.eql(false);
|
|
||||||
spamPrevention.userLogin().reset.called.should.eql(true);
|
|
||||||
done();
|
|
||||||
} catch (err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Can\'t generate access token without client.', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.client = {
|
|
||||||
slug: 'test'
|
|
||||||
};
|
|
||||||
|
|
||||||
req.authInfo = {ip: '127.0.0.1'};
|
|
||||||
req.body.grant_type = 'password';
|
|
||||||
req.body.username = 'username';
|
|
||||||
req.body.password = 'password';
|
|
||||||
res.setHeader = {};
|
|
||||||
res.end = {};
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, function (err) {
|
|
||||||
err.errorType.should.eql('UnauthorizedError');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Can\'t generate access token without username.', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
|
|
||||||
req.authInfo = {ip: '127.0.0.1'};
|
|
||||||
req.body.grant_type = 'password';
|
|
||||||
req.body.password = 'password';
|
|
||||||
|
|
||||||
res.setHeader = {};
|
|
||||||
res.end = {};
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, function (err) {
|
|
||||||
err.errorType.should.eql('BadRequestError');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Can\'t generate access token without password.', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
|
|
||||||
req.authInfo = {ip: '127.0.0.1'};
|
|
||||||
req.body.grant_type = 'password';
|
|
||||||
req.body.username = 'username';
|
|
||||||
|
|
||||||
res.setHeader = {};
|
|
||||||
res.end = {};
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, function (err) {
|
|
||||||
err.errorType.should.eql('BadRequestError');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Handles database error.', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.client = {
|
|
||||||
slug: 'test'
|
|
||||||
};
|
|
||||||
|
|
||||||
req.authInfo = {ip: '127.0.0.1'};
|
|
||||||
req.body.grant_type = 'password';
|
|
||||||
req.body.username = 'username';
|
|
||||||
req.body.password = 'password';
|
|
||||||
req.client = {
|
|
||||||
id: 1
|
|
||||||
};
|
|
||||||
res.setHeader = {};
|
|
||||||
res.end = {};
|
|
||||||
|
|
||||||
sinon.stub(models.User, 'check')
|
|
||||||
.withArgs({email: 'username', password: 'password'}).returns(new Promise.resolve({
|
|
||||||
id: 1
|
|
||||||
}));
|
|
||||||
|
|
||||||
sinon.stub(authUtils, 'createTokens')
|
|
||||||
.returns(new Promise.reject({
|
|
||||||
message: 'DB error'
|
|
||||||
}));
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, function (err) {
|
|
||||||
err.message.should.eql('DB error');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Generate Token from Refreshtoken', function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
sinon.stub(models.Accesstoken, 'destroyAllExpired')
|
|
||||||
.returns(new Promise.resolve());
|
|
||||||
sinon.stub(models.Refreshtoken, 'destroyAllExpired')
|
|
||||||
.returns(new Promise.resolve());
|
|
||||||
|
|
||||||
oAuth.init();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Successfully generate access token.', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.client = {
|
|
||||||
slug: 'test'
|
|
||||||
};
|
|
||||||
req.authInfo = {ip: '127.0.0.1'};
|
|
||||||
req.connection = {remoteAddress: '127.0.0.1'};
|
|
||||||
req.body.grant_type = 'refresh_token';
|
|
||||||
req.body.refresh_token = 'token';
|
|
||||||
res.setHeader = function () {
|
|
||||||
};
|
|
||||||
res.end = function () {
|
|
||||||
};
|
|
||||||
|
|
||||||
sinon.stub(models.Refreshtoken, 'findOne')
|
|
||||||
.withArgs({token: 'token'}).returns(new Promise.resolve({
|
|
||||||
toJSON: function () {
|
|
||||||
return {
|
|
||||||
expires: Date.now() + 3600
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
sinon.stub(authUtils, 'createTokens')
|
|
||||||
.returns(new Promise.resolve({
|
|
||||||
access_token: 'AT',
|
|
||||||
refresh_token: 'RT',
|
|
||||||
expires_in: Date.now() + 1000
|
|
||||||
}));
|
|
||||||
|
|
||||||
sinon.stub(res, 'setHeader').callsFake(function () {
|
|
||||||
});
|
|
||||||
|
|
||||||
sinon.stub(res, 'end').callsFake(function (json) {
|
|
||||||
try {
|
|
||||||
should.exist(json);
|
|
||||||
json = JSON.parse(json);
|
|
||||||
json.should.have.property('access_token');
|
|
||||||
json.should.have.property('expires_in');
|
|
||||||
json.should.have.property('token_type', 'Bearer');
|
|
||||||
next.called.should.eql(false);
|
|
||||||
done();
|
|
||||||
} catch (err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Can\'t generate access token without valid refresh token.', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.client = {
|
|
||||||
slug: 'test'
|
|
||||||
};
|
|
||||||
req.connection = {remoteAddress: '127.0.0.1'};
|
|
||||||
req.authInfo = {ip: '127.0.0.1'};
|
|
||||||
req.body.grant_type = 'refresh_token';
|
|
||||||
req.body.refresh_token = 'token';
|
|
||||||
res.setHeader = {};
|
|
||||||
res.end = {};
|
|
||||||
|
|
||||||
sinon.stub(models.Refreshtoken, 'findOne')
|
|
||||||
.withArgs({token: 'token'}).returns(new Promise.resolve());
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, function (err) {
|
|
||||||
err.errorType.should.eql('NoPermissionError');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Can\'t generate access token with expired refresh token.', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.client = {
|
|
||||||
slug: 'test'
|
|
||||||
};
|
|
||||||
req.connection = {remoteAddress: '127.0.0.1'};
|
|
||||||
req.authInfo = {ip: '127.0.0.1'};
|
|
||||||
req.body.grant_type = 'refresh_token';
|
|
||||||
req.body.refresh_token = 'token';
|
|
||||||
res.setHeader = {};
|
|
||||||
res.end = {};
|
|
||||||
|
|
||||||
sinon.stub(models.Refreshtoken, 'findOne')
|
|
||||||
.withArgs({token: 'token'}).returns(new Promise.resolve({
|
|
||||||
toJSON: function () {
|
|
||||||
return {
|
|
||||||
expires: Date.now() - 3600
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, function (err) {
|
|
||||||
err.errorType.should.eql('UnauthorizedError');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Handles database error.', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.client = {
|
|
||||||
slug: 'test'
|
|
||||||
};
|
|
||||||
req.connection = {remoteAddress: '127.0.0.1'};
|
|
||||||
req.authInfo = {ip: '127.0.0.1'};
|
|
||||||
req.body.grant_type = 'refresh_token';
|
|
||||||
req.body.refresh_token = 'token';
|
|
||||||
res.setHeader = {};
|
|
||||||
res.end = {};
|
|
||||||
|
|
||||||
sinon.stub(models.Refreshtoken, 'findOne')
|
|
||||||
.withArgs({token: 'token'}).returns(new Promise.resolve({
|
|
||||||
toJSON: function () {
|
|
||||||
return {
|
|
||||||
expires: Date.now() + 3600
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
sinon.stub(authUtils, 'createTokens').callsFake(function () {
|
|
||||||
return Promise.reject(new Error('DB error'));
|
|
||||||
});
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, function (err) {
|
|
||||||
err.stack.should.containEql('DB error');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Generate Token from Authorization Code', function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
sinon.stub(models.Accesstoken, 'destroyAllExpired')
|
|
||||||
.returns(new Promise.resolve());
|
|
||||||
|
|
||||||
sinon.stub(models.Refreshtoken, 'destroyAllExpired')
|
|
||||||
.returns(new Promise.resolve());
|
|
||||||
|
|
||||||
oAuth.init();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Successfully generate access token.', function (done) {
|
|
||||||
var user = new models.User(testUtils.DataGenerator.forKnex.createUser());
|
|
||||||
|
|
||||||
req.body = {};
|
|
||||||
req.query = {};
|
|
||||||
req.client = {
|
|
||||||
id: 1
|
|
||||||
};
|
|
||||||
req.authInfo = {ip: '127.0.0.1'};
|
|
||||||
req.connection = {remoteAddress: '127.0.0.1'};
|
|
||||||
req.body.grant_type = 'authorization_code';
|
|
||||||
req.body.authorizationCode = '1234';
|
|
||||||
|
|
||||||
res.json = function (data) {
|
|
||||||
data.access_token.should.eql('access-token');
|
|
||||||
data.refresh_token.should.eql('refresh-token');
|
|
||||||
data.expires_in.should.eql(10);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
sinon.stub(authUtils, 'createTokens')
|
|
||||||
.returns(new Promise.resolve({
|
|
||||||
access_token: 'access-token',
|
|
||||||
refresh_token: 'refresh-token',
|
|
||||||
expires_in: 10
|
|
||||||
}));
|
|
||||||
|
|
||||||
sinon.stub(passport, 'authenticate').callsFake(function (name, options, onSuccess) {
|
|
||||||
return function () {
|
|
||||||
onSuccess(null, user);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Error: ghost.org', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.query = {};
|
|
||||||
req.client = {
|
|
||||||
id: 1
|
|
||||||
};
|
|
||||||
|
|
||||||
req.authInfo = {ip: '127.0.0.1'};
|
|
||||||
req.connection = {remoteAddress: '127.0.0.1'};
|
|
||||||
req.body.grant_type = 'authorization_code';
|
|
||||||
req.body.authorizationCode = '1234';
|
|
||||||
|
|
||||||
sinon.stub(passport, 'authenticate').callsFake(function (name, options, onSuccess) {
|
|
||||||
return function () {
|
|
||||||
onSuccess(new common.errors.UnauthorizedError());
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, function (err) {
|
|
||||||
should.exist(err);
|
|
||||||
(err instanceof common.errors.UnauthorizedError).should.eql(true);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Error: no authorization_code provided', function (done) {
|
|
||||||
req.body = {};
|
|
||||||
req.query = {};
|
|
||||||
req.client = {
|
|
||||||
id: 1
|
|
||||||
};
|
|
||||||
req.connection = {remoteAddress: '127.0.0.1'};
|
|
||||||
req.body.grant_type = 'authorization_code';
|
|
||||||
|
|
||||||
oAuth.generateAccessToken(req, res, function (err) {
|
|
||||||
should.exist(err);
|
|
||||||
(err instanceof common.errors.UnauthorizedError).should.eql(true);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,22 +0,0 @@
|
|||||||
var should = require('should'),
|
|
||||||
sinon = require('sinon'),
|
|
||||||
passport = require('passport'),
|
|
||||||
ghostPassport = require('../../../../server/services/auth/passport');
|
|
||||||
|
|
||||||
describe('Ghost Passport', function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
sinon.spy(passport, 'use');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
sinon.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('[default] local auth', function () {
|
|
||||||
it('initialise passport with passport auth type', function () {
|
|
||||||
var response = ghostPassport.init();
|
|
||||||
should.exist(response);
|
|
||||||
passport.use.callCount.should.eql(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user