Change auth strategy (#174)

This commit is contained in:
Abenezer Melkamu
2024-03-21 21:36:00 +03:00
committed by GitHub
parent 0f9d913104
commit a643fbcfc2
11 changed files with 84 additions and 23 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "soul-cli", "name": "soul-cli",
"version": "0.7.1", "version": "0.7.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "soul-cli", "name": "soul-cli",
"version": "0.7.1", "version": "0.7.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",

View File

@@ -1,6 +1,6 @@
{ {
"name": "soul-cli", "name": "soul-cli",
"version": "0.7.1", "version": "0.7.2",
"description": "A SQLite REST and Realtime server", "description": "A SQLite REST and Realtime server",
"main": "src/server.js", "main": "src/server.js",
"bin": { "bin": {

View File

@@ -7,8 +7,7 @@ const runCLICommands = () => {
// if the updatesuperuser command is passed from the CLI execute the updatesuperuser function // if the updatesuperuser command is passed from the CLI execute the updatesuperuser function
if (argv._.includes('updatesuperuser')) { if (argv._.includes('updatesuperuser')) {
const { id, password, is_superuser } = argv; const { id, password, is_superuser } = argv;
if (!password && is_superuser === undefined) {
if (!password && !is_superuser) {
console.log( console.log(
'Please provide either the --password or --is_superuser flag when using the updateuser command.', 'Please provide either the --password or --is_superuser flag when using the updateuser command.',
); );

View File

@@ -76,10 +76,10 @@ const createDefaultTables = async () => {
permissions.push({ permissions.push({
role_id: roleId, role_id: roleId,
table_name: table.name, table_name: table.name,
create: 'false', create: 0,
read: 'true', read: 1,
update: 'false', update: 0,
delete: 'false', delete: 0,
}); });
} }

View File

@@ -55,7 +55,7 @@ const obtainAccessToken = async (req, res) => {
*/ */
} }
let permissions, roleIds; let roleIds;
// if the user is not a superuser get the role and its permission from the DB // if the user is not a superuser get the role and its permission from the DB
if (!toBoolean(user.is_superuser)) { if (!toBoolean(user.is_superuser)) {
@@ -64,7 +64,6 @@ const obtainAccessToken = async (req, res) => {
res, res,
}); });
permissions = roleData.permissions;
roleIds = roleData.roleIds; roleIds = roleData.roleIds;
} }
@@ -73,7 +72,6 @@ const obtainAccessToken = async (req, res) => {
userId: user.id, userId: user.id,
isSuperuser: user.is_superuser, isSuperuser: user.is_superuser,
roleIds, roleIds,
permissions,
}; };
// generate an access token // generate an access token
@@ -151,7 +149,7 @@ const refreshAccessToken = async (req, res) => {
*/ */
} }
let permissions, roleIds; let roleIds;
const user = users[0]; const user = users[0];
// if the user is not a superuser get the role and its permission from the DB // if the user is not a superuser get the role and its permission from the DB
@@ -161,7 +159,6 @@ const refreshAccessToken = async (req, res) => {
res, res,
}); });
permissions = roleData.permissions;
roleIds = roleData.roleIds; roleIds = roleData.roleIds;
} }
@@ -170,7 +167,6 @@ const refreshAccessToken = async (req, res) => {
userId: user.id, userId: user.id,
isSuperuser: user.is_superuser, isSuperuser: user.is_superuser,
roleIds, roleIds,
permissions,
}; };
// generate an access token // generate an access token

View File

@@ -25,7 +25,7 @@ const updateSuperuser = async (fields) => {
try { try {
// find the user by using the id field // find the user by using the id field
const users = authService.getRoleByUserId({ id }); const users = authService.getUsersById({ userId: id });
// abort if the id is invalid // abort if the id is invalid
if (users.length === 0) { if (users.length === 0) {

View File

@@ -657,7 +657,7 @@ const updateRowInTableByPK = async (req, res, next) => {
if (typeof value === 'string') { if (typeof value === 'string') {
value = `'${value}'`; value = `'${value}'`;
} }
return `${key} = ${value}`; return `'${key}' = ${value}`;
}) })
.join(', '); .join(', ');

View File

@@ -6,9 +6,16 @@ const {
responseMessages, responseMessages,
} = require('../constants/'); } = require('../constants/');
const { removeFields } = require('../utils'); const { removeFields } = require('../utils');
const { customValidator } = require('../middlewares/validation');
const schema = require('../schemas/auth');
const { httpVerbs } = apiConstants; const { httpVerbs } = apiConstants;
const { reservedTableNames, USERS_TABLE, tableFields } = dbConstants; const {
reservedTableNames,
USERS_TABLE,
ROLES_PERMISSIONS_TABLE,
tableFields,
} = dbConstants;
const { errorMessage } = responseMessages; const { errorMessage } = responseMessages;
const processRowRequest = async (req, res, next) => { const processRowRequest = async (req, res, next) => {
@@ -39,6 +46,21 @@ const processRowRequest = async (req, res, next) => {
); );
} }
// Validate fields for the _roles_permission API on POST and PUT requests
if (
resource === ROLES_PERMISSIONS_TABLE &&
(method === httpVerbs.POST || method === httpVerbs.PUT)
) {
const validation = customValidator(schema.updateRolePermissions)(req);
if (validation.errorStatus) {
return res.status(400).json({
message: validation.message,
error: validation.details,
});
}
}
next(); next();
}; };

View File

@@ -1,6 +1,7 @@
const config = require('../config'); const config = require('../config');
const { decodeToken, toBoolean } = require('../utils/index'); const { decodeToken, toBoolean } = require('../utils/index');
const { apiConstants, responseMessages } = require('../constants'); const { apiConstants, responseMessages } = require('../constants');
const { authService } = require('../services');
const { errorMessage } = responseMessages; const { errorMessage } = responseMessages;
@@ -42,12 +43,16 @@ const hasAccess = async (req, res, next) => {
.send({ message: errorMessage.NOT_AUTHORIZED_ERROR }); .send({ message: errorMessage.NOT_AUTHORIZED_ERROR });
} }
// if the user is not a super user, check the users permission on the resource // if the user is not a super user, fetch the permission of the user from the DB
const permissions = payload.permissions.filter((row) => { const rolePermissions = authService.getPermissionByRoleIds({
return row.table_name === tableName; roleIds: payload.roleIds,
}); });
if (permissions.length <= 0) { const resourcePermission = rolePermissions.filter(
(row) => row.table_name === tableName,
);
if (resourcePermission.length <= 0) {
return res return res
.status(403) .status(403)
.send({ message: errorMessage.PERMISSION_NOT_DEFINED_ERROR }); .send({ message: errorMessage.PERMISSION_NOT_DEFINED_ERROR });
@@ -56,7 +61,7 @@ const hasAccess = async (req, res, next) => {
// If the user has permission on the table in at least in one of the roles then allow access on the table // If the user has permission on the table in at least in one of the roles then allow access on the table
let hasPermission = false; let hasPermission = false;
permissions.some((resource) => { resourcePermission.some((resource) => {
const httpMethod = const httpMethod =
apiConstants.httpMethodDefinitions[verb].toLowerCase(); apiConstants.httpMethodDefinitions[verb].toLowerCase();

View File

@@ -19,6 +19,24 @@ const validator = (schema) => (req, res, next) => {
} }
}; };
const customValidator = (schema) => (req) => {
const response = { errorStatus: false, message: '', error: '' };
const { body, params, query, cookies } = req;
const data = { body, params, query, cookies };
const { error } = schema.validate(data);
if (error) {
response.errorStatus = true;
response.message = error.message;
response.error = error.details;
}
return response;
};
module.exports = { module.exports = {
validator, validator,
customValidator,
}; };

View File

@@ -59,9 +59,30 @@ const registerUser = Joi.object({
}).required(), }).required(),
}); });
const updateRolePermissions = Joi.object({
query: Joi.object({}).required(),
params: Joi.object({ name: Joi.string(), pks: Joi.string() }).required(),
body: Joi.object({
fields: Joi.object({
role_id: Joi.number().required(),
table_name: Joi.string().required(),
create: Joi.number().valid(0, 1).required(),
read: Joi.number().valid(0, 1).required(),
update: Joi.number().valid(0, 1).required(),
delete: Joi.number().valid(0, 1).required(),
}).required(),
}).required(),
cookies: Joi.object({
accessToken: Joi.string().required(),
refreshToken: Joi.string().optional(),
}).required(),
});
module.exports = { module.exports = {
obtainAccessToken, obtainAccessToken,
refreshAccessToken, refreshAccessToken,
changePassword, changePassword,
registerUser, registerUser,
updateRolePermissions,
}; };