Skip to content

Commit

Permalink
Remove usage of kuzzle package (#83)
Browse files Browse the repository at this point in the history
The plugin was using classes from the kuzzle package.

Since this plugin is not used in an application with kuzzle but directly into the core, there is no package named kuzzle available since we are inside this package.

This is a "pansement" just to be able to release Kuzzle 2.14.1 but this plugin should be added directly into the core.
  • Loading branch information
Aschen authored Sep 9, 2021
1 parent 693c3b9 commit d8ddadf
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 50 deletions.
58 changes: 26 additions & 32 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@ const debug = require('debug')('kuzzle-plugin-auth-passport-local');
const jsonwebtoken = require('jsonwebtoken');
const ms = require('ms');
const { Strategy: LocalStrategy } = require('passport-local');
const {
KuzzleRequest,
BadRequestError,
ForbiddenError,
PreconditionError
} = require('kuzzle');

const getUserConstructor = require('./getUserConstructor');
const PasswordManager = require('./passwordManager');
Expand Down Expand Up @@ -304,13 +298,13 @@ class AuthenticationPlugin {
debug('validate(kuid = %s, isUpdate = %s)', kuid, isUpdate);

if (credentials.kuid) {
throw new BadRequestError('kuid cannot be specified in credentials.');
throw new this.context.errors.BadRequestError('kuid cannot be specified in credentials.');
}

if (credentials.username) {
const userByName = await this.getUsersRepository().get(credentials.username);
if (userByName !== null && kuid !== userByName.kuid) {
throw new PreconditionError(`Login "${credentials.username}" is already used.`);
throw new this.context.errors.PreconditionError(`Login "${credentials.username}" is already used.`);
}
}

Expand Down Expand Up @@ -387,13 +381,13 @@ class AuthenticationPlugin {
*/
async create (request, credentials, kuid) {
if (!credentials.password) {
throw new BadRequestError('Password needed.');
throw new this.context.errors.BadRequestError('Password needed.');
}

const exists = await this.exists(request, kuid);

if (exists) {
throw new PreconditionError(`A strategy already exists for user "${kuid}".`);
throw new this.context.errors.PreconditionError(`A strategy already exists for user "${kuid}".`);
}

credentials.userSalt = crypto.randomBytes(128).toString('hex');
Expand Down Expand Up @@ -425,7 +419,7 @@ class AuthenticationPlugin {
*/
async update (request, credentials, kuid) {
if (credentials.kuid) {
throw new BadRequestError('The request must not contain a kuid attribute.');
throw new this.context.errors.BadRequestError('The request must not contain a kuid attribute.');
}

const user = await this.getCredentialsFromUserId(kuid);
Expand All @@ -436,7 +430,7 @@ class AuthenticationPlugin {
// "invalid user or password" message before this check in case someone
// tries to guess if a username exists using this route
if (user === null) {
throw new PreconditionError(`No credentials found for user "${kuid}".`);
throw new this.context.errors.PreconditionError(`No credentials found for user "${kuid}".`);
}

const credentialUpdate = {};
Expand Down Expand Up @@ -507,7 +501,7 @@ class AuthenticationPlugin {
await this.passwordRequiredCheck(request, user);

if (user === null) {
throw new PreconditionError(`No credentials found for user "${kuid}".`);
throw new this.context.errors.PreconditionError(`No credentials found for user "${kuid}".`);
}

return this.getUsersRepository().delete(user._id, {refresh: 'wait_for'});
Expand Down Expand Up @@ -535,9 +529,9 @@ class AuthenticationPlugin {
else if (! keywordWhitelist.includes(key)) {
const forbiddenFields = extractESMappingFields(storageMapping.users);
if (forbiddenFields.includes(key)) {
throw new ForbiddenError(`Forbidden field "${key}". Only the "username" or "kuid" fields are sortable and only the first is also searchable.`);
throw new this.context.errors.ForbiddenError(`Forbidden field "${key}". Only the "username" or "kuid" fields are sortable and only the first is also searchable.`);
}
throw new BadRequestError(`The "${key}" keyword is not allowed in this search query for security concerns.`);
throw new this.context.errors.BadRequestError(`The "${key}" keyword is not allowed in this search query for security concerns.`);
}
return {};
};
Expand Down Expand Up @@ -571,7 +565,7 @@ class AuthenticationPlugin {
const user = await this.getUsersRepository().get(username);

if (user === null) {
throw new PreconditionError(`No credentials found for username "${username}".`);
throw new this.context.errors.PreconditionError(`No credentials found for username "${username}".`);
}

return this.outputDocument(user);
Expand All @@ -586,7 +580,7 @@ class AuthenticationPlugin {
const user = await this.getCredentialsFromUserId(kuid);

if (user === null) {
throw new PreconditionError(`No credentials found for user "${kuid}".`);
throw new this.context.errors.PreconditionError(`No credentials found for user "${kuid}".`);
}

return this.outputDocument(user);
Expand Down Expand Up @@ -656,13 +650,13 @@ class AuthenticationPlugin {
}

if (typeof password !== 'string' || password.length === 0) {
throw new BadRequestError('Cannot update credentials: password required.');
throw new this.context.errors.BadRequestError('Cannot update credentials: password required.');
}

const isValid = await this.passwordManager.checkPassword(password, user);

if (user === null || isValid === false) {
throw new ForbiddenError('Invalid user or password.');
throw new this.context.errors.ForbiddenError('Invalid user or password.');
}
}

Expand All @@ -676,13 +670,13 @@ class AuthenticationPlugin {
const { _id: kuid } = request.input.resource;

if (!kuid) {
throw new BadRequestError('Missing kuid');
throw new this.context.errors.BadRequestError('Missing kuid');
}
// type checking is alredy done at Request level

const user = await this.getCredentialsFromUserId(kuid);
if (!user) {
throw new BadRequestError('Invalid kuid given');
throw new this.context.errors.BadRequestError('Invalid kuid given');
}

return {
Expand All @@ -696,7 +690,7 @@ class AuthenticationPlugin {
*/
async resetPasswordAction (request) {
if (!request.input.body) {
throw new BadRequestError('Missing request body');
throw new this.context.errors.BadRequestError('Missing request body');
}

const {
Expand All @@ -705,16 +699,16 @@ class AuthenticationPlugin {
} = request.input.body;

if (!password) {
throw new BadRequestError('Missing "password" attribute');
throw new this.context.errors.BadRequestError('Missing "password" attribute');
}
if (typeof password !== 'string' || password.trim() === '') {
throw new BadRequestError('Invalid password supplied. Must be a non-empty string');
throw new this.context.errors.BadRequestError('Invalid password supplied. Must be a non-empty string');
}
if (!token) {
throw new BadRequestError('Missing "token" attribute');
throw new this.context.errors.BadRequestError('Missing "token" attribute');
}
if (typeof token !== 'string') {
throw new BadRequestError('Invalid token supplied');
throw new this.context.errors.BadRequestError('Invalid token supplied');
}

let kuid;
Expand All @@ -730,15 +724,15 @@ class AuthenticationPlugin {
throw this.context.errorsManager.get('invalid_token');
}

throw new BadRequestError(e.message);
throw new this.context.errors.BadRequestError(e.message);
}

await this.validate(request, {password}, kuid, 'local', true);
await this.update(request, {password}, kuid);

const user = await this.getCredentialsFromUserId(kuid);

const loginRequest = new KuzzleRequest({
const loginRequest = new this.context.constructors.Request({
action: 'login',
body: {
password,
Expand Down Expand Up @@ -777,17 +771,17 @@ class AuthenticationPlugin {
*/
async _validateCreate(credentials, kuid) {
if (!credentials.username) {
throw new BadRequestError('Username required.');
throw new this.context.errors.BadRequestError('Username required.');
}

if (!credentials.password) {
throw new BadRequestError('Password required.');
throw new this.context.errors.BadRequestError('Password required.');
}

const user = await this.getUsersRepository().get(credentials.username);

if (user !== null && kuid !== user.kuid) {
throw new PreconditionError(`Login "${credentials.username}" is already used.`);
throw new this.context.errors.PreconditionError(`Login "${credentials.username}" is already used.`);
}

const newUser = new this.User();
Expand All @@ -805,7 +799,7 @@ class AuthenticationPlugin {
*/
async _validateUpdate(credentials, kuid) {
if (!credentials.username && !credentials.password) {
throw new BadRequestError('Missing username or password.');
throw new this.context.errors.BadRequestError('Missing username or password.');
}

const user = await this.getCredentialsFromUserId(kuid);
Expand Down
8 changes: 4 additions & 4 deletions test/getResetPasswordTokenAction.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const jsonwebtoken = require('jsonwebtoken');
const should = require('should');
const { KuzzleRequest, BadRequestError } = require('kuzzle');
const { KuzzleRequest } = require('kuzzle');

const PluginLocal = require('../lib');
const PluginContext = require('./mock/pluginContext.mock.js');
Expand All @@ -26,14 +26,14 @@ describe('#getResetPasswordTokenAction', () => {
const req = new KuzzleRequest({});

return should(pluginLocal.getResetPasswordTokenAction(req))
.be.rejectedWith(BadRequestError);
.be.rejected();
});

it('should throw if the kuid is an empty string', () => {
request.input.resource._id = '';

return should(pluginLocal.getResetPasswordTokenAction(request))
.be.rejectedWith(BadRequestError);
.be.rejected();
});

it('should throw if the user does not exist', () => {
Expand All @@ -43,7 +43,7 @@ describe('#getResetPasswordTokenAction', () => {
});

return should(pluginLocal.getResetPasswordTokenAction(request))
.be.rejectedWith(BadRequestError);
.be.rejected();
});

it('should return a token if the kuid is valid', async () => {
Expand Down
5 changes: 3 additions & 2 deletions test/mock/pluginContext.mock.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const
sinon = require('sinon'),
{ Request, errors } = require('kuzzle-common-objects'),
{ errors } = require('kuzzle-common-objects'),
{ KuzzleRequest } = require('kuzzle'),
manifest = require('../../manifest.json');

const getError = id => {
Expand Down Expand Up @@ -48,7 +49,7 @@ module.exports = function PluginContext() {
this.create = sinon.stub().resolves();
this.get = sinon.stub().resolves();
},
Request
Request: KuzzleRequest
},
errors,
errorsManager: {
Expand Down
14 changes: 7 additions & 7 deletions test/resetPasswordAction.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const jsonwebtoken = require('jsonwebtoken');
const should = require('should');
const sinon = require('sinon');
const { KuzzleRequest, BadRequestError } = require('kuzzle');
const { KuzzleRequest } = require('kuzzle');

const PluginLocal = require('../lib');
const PluginContext = require('./mock/pluginContext.mock.js');
Expand Down Expand Up @@ -37,42 +37,42 @@ describe('#resetPasswordAction', () => {
const req = new KuzzleRequest({});

return should(pluginLocal.resetPasswordAction(req))
.be.rejectedWith(BadRequestError);
.be.rejected();
});

it('should throw if password is not set', () => {
delete request.input.body.password;

return should(pluginLocal.resetPasswordAction(request))
.be.rejectedWith(BadRequestError);
.be.rejected();
});

it('should throw if password is not a string', () => {
request.input.body.password = [];

return should(pluginLocal.resetPasswordAction(request))
.be.rejectedWith(BadRequestError);
.be.rejected();
});

it('should throw if the password is an empty string', () => {
request.input.body.password = ' ';

return should(pluginLocal.resetPasswordAction(request))
.be.rejectedWith(BadRequestError);
.be.rejected();
});

it('should throw if the token is missing', () => {
delete request.input.body.token;

return should(pluginLocal.resetPasswordAction(request))
.be.rejectedWith(BadRequestError);
.be.rejected();
});

it('should throw if the token is not a string', () => {
request.input.body.token = true;

return should(pluginLocal.resetPasswordAction(request))
.be.rejectedWith(BadRequestError);
.be.rejected();
});

it('should update the password when ok', async () => {
Expand Down
17 changes: 12 additions & 5 deletions test/search.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const should = require('should');
const { BadRequestError, ForbiddenError } = require('kuzzle');

const PluginLocal = require('../lib');
const PluginContext = require('./mock/pluginContext.mock.js');
Expand Down Expand Up @@ -37,7 +36,9 @@ describe('#search', () => {
searchBody.query.match = { algorithm: 'sha512' };

return should(pluginLocal.search(searchBody))
.be.rejectedWith(new ForbiddenError('Forbidden field "algorithm". Only the "username" or "kuid" fields are sortable and only the first is also searchable.'));
.be.rejectedWith({
message: 'Forbidden field "algorithm". Only the "username" or "kuid" fields are sortable and only the first is also searchable.'
});
});

it('should throw an error if the query contains forbidden keyword', () => {
Expand All @@ -49,14 +50,18 @@ describe('#search', () => {
};

return should(pluginLocal.search(searchBody))
.be.rejectedWith(new BadRequestError('The "multi_match" keyword is not allowed in this search query for security concerns.'));
.be.rejectedWith({
message: 'The "multi_match" keyword is not allowed in this search query for security concerns.'
});
});

it('should throw an error if the sort contains forbidden fields', () => {
searchBody.sort = [{ 'passwordHistory.userSalt': 'asc' }];

return should(pluginLocal.search(searchBody))
.be.rejectedWith(new ForbiddenError('Forbidden field "passwordHistory.userSalt". Only the "username" or "kuid" fields are sortable and only the first is also searchable.'));
.be.rejectedWith({
message: 'Forbidden field "passwordHistory.userSalt". Only the "username" or "kuid" fields are sortable and only the first is also searchable.'
});
});

it('should throw an error if the sort contains forbidden keyword', () => {
Expand All @@ -73,7 +78,9 @@ describe('#search', () => {
};

return should(pluginLocal.search(searchBody))
.be.rejectedWith(new BadRequestError('The "_script" keyword is not allowed in this search query for security concerns.'));
.be.rejectedWith({
message: 'The "_script" keyword is not allowed in this search query for security concerns.'
});
});

it('should ignore forbidden fields when being used as a simple value', async () => {
Expand Down

0 comments on commit d8ddadf

Please sign in to comment.