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",
"version": "0.7.1",
"version": "0.7.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "soul-cli",
"version": "0.7.1",
"version": "0.7.2",
"license": "MIT",
"dependencies": {
"bcrypt": "^5.1.1",

View File

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

View File

@@ -7,8 +7,7 @@ const runCLICommands = () => {
// if the updatesuperuser command is passed from the CLI execute the updatesuperuser function
if (argv._.includes('updatesuperuser')) {
const { id, password, is_superuser } = argv;
if (!password && !is_superuser) {
if (!password && is_superuser === undefined) {
console.log(
'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({
role_id: roleId,
table_name: table.name,
create: 'false',
read: 'true',
update: 'false',
delete: 'false',
create: 0,
read: 1,
update: 0,
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 (!toBoolean(user.is_superuser)) {
@@ -64,7 +64,6 @@ const obtainAccessToken = async (req, res) => {
res,
});
permissions = roleData.permissions;
roleIds = roleData.roleIds;
}
@@ -73,7 +72,6 @@ const obtainAccessToken = async (req, res) => {
userId: user.id,
isSuperuser: user.is_superuser,
roleIds,
permissions,
};
// generate an access token
@@ -151,7 +149,7 @@ const refreshAccessToken = async (req, res) => {
*/
}
let permissions, roleIds;
let roleIds;
const user = users[0];
// 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,
});
permissions = roleData.permissions;
roleIds = roleData.roleIds;
}
@@ -170,7 +167,6 @@ const refreshAccessToken = async (req, res) => {
userId: user.id,
isSuperuser: user.is_superuser,
roleIds,
permissions,
};
// generate an access token

View File

@@ -25,7 +25,7 @@ const updateSuperuser = async (fields) => {
try {
// 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
if (users.length === 0) {

View File

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

View File

@@ -6,9 +6,16 @@ const {
responseMessages,
} = require('../constants/');
const { removeFields } = require('../utils');
const { customValidator } = require('../middlewares/validation');
const schema = require('../schemas/auth');
const { httpVerbs } = apiConstants;
const { reservedTableNames, USERS_TABLE, tableFields } = dbConstants;
const {
reservedTableNames,
USERS_TABLE,
ROLES_PERMISSIONS_TABLE,
tableFields,
} = dbConstants;
const { errorMessage } = responseMessages;
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();
};

View File

@@ -1,6 +1,7 @@
const config = require('../config');
const { decodeToken, toBoolean } = require('../utils/index');
const { apiConstants, responseMessages } = require('../constants');
const { authService } = require('../services');
const { errorMessage } = responseMessages;
@@ -42,12 +43,16 @@ const hasAccess = async (req, res, next) => {
.send({ message: errorMessage.NOT_AUTHORIZED_ERROR });
}
// if the user is not a super user, check the users permission on the resource
const permissions = payload.permissions.filter((row) => {
return row.table_name === tableName;
// if the user is not a super user, fetch the permission of the user from the DB
const rolePermissions = authService.getPermissionByRoleIds({
roleIds: payload.roleIds,
});
if (permissions.length <= 0) {
const resourcePermission = rolePermissions.filter(
(row) => row.table_name === tableName,
);
if (resourcePermission.length <= 0) {
return res
.status(403)
.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
let hasPermission = false;
permissions.some((resource) => {
resourcePermission.some((resource) => {
const httpMethod =
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 = {
validator,
customValidator,
};

View File

@@ -59,9 +59,30 @@ const registerUser = Joi.object({
}).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 = {
obtainAccessToken,
refreshAccessToken,
changePassword,
registerUser,
updateRolePermissions,
};