From 796f0b32f3192a1a8b712f087641eac0c6c7fc14 Mon Sep 17 00:00:00 2001 From: Nicola Carminati Date: Fri, 26 Apr 2019 19:22:54 +0200 Subject: [PATCH] Advanced User Management --- .../Controllers/FunctionsAccessController.cs | 4 +- .../Controllers/MachinesUsersController.cs | 10 +++-- Step.Database/Controllers/UsersController.cs | 43 +++++++++++++------ Step.Database/DatabaseContext.cs | 9 +++- Step.Database/Migrations/Configuration.cs | 30 ++++++++++--- Step.Model/Constants.cs | 13 +++--- Step.Model/DTOModels/DTORoleModel.cs | 1 + Step/Controllers/WebApi/UserController.cs | 4 ++ .../wwwroot/src/@types/signalr.functions.d.ts | 6 +-- Step/wwwroot/src/services/hub.ts | 2 +- Step/wwwroot/src/services/loginService.ts | 12 +++++- Step/wwwroot/src/store/machineStatus.store.ts | 30 +++++++++++-- 12 files changed, 122 insertions(+), 42 deletions(-) diff --git a/Step.Database/Controllers/FunctionsAccessController.cs b/Step.Database/Controllers/FunctionsAccessController.cs index 8afbb200..2e241ed9 100644 --- a/Step.Database/Controllers/FunctionsAccessController.cs +++ b/Step.Database/Controllers/FunctionsAccessController.cs @@ -42,8 +42,8 @@ namespace Step.Database.Controllers Name = f.Name, Area = f.Area, Enabled = f.Enabled, - CanRead = f.ReadLevelMin < roleLevel, - CanWrite = f.WriteLevelMin < roleLevel + CanRead = f.ReadLevelMin <= roleLevel, + CanWrite = f.WriteLevelMin <= roleLevel }) .ToList(); } diff --git a/Step.Database/Controllers/MachinesUsersController.cs b/Step.Database/Controllers/MachinesUsersController.cs index b5bb96a3..7e19a5b8 100644 --- a/Step.Database/Controllers/MachinesUsersController.cs +++ b/Step.Database/Controllers/MachinesUsersController.cs @@ -76,7 +76,8 @@ namespace Step.Database.Controllers return new DTORoleModel() { Id = role.RoleId, - Name = role.Name + Name = role.Name, + Level = role.Level }; } @@ -86,7 +87,7 @@ namespace Step.Database.Controllers public bool UserIsCmsAdmin(int machineId, int userId) { MachineUserModel user = FindByUserId(machineId, userId); - if (user.Role.RoleId == (int)ROLE_IDS.CMS_SERVICE_ONLY) + if (user.Role.RoleId == (int)ROLE_IDS.CMS_SERVICE || user.Role.RoleId == (int)ROLE_IDS.CMS_UT) return true; return false; @@ -108,12 +109,13 @@ namespace Step.Database.Controllers public List GetRolesList() { return dbCtx - .Roles + .Roles.Where(X => X.Level < MIN_CMS_ROLE) .Select(x => new DTORoleModel() { Id = x.RoleId, Name = x.Name - }).ToList(); + }) + .ToList(); } public void UpdateUserRole(int machineId, int userId, int roleId) diff --git a/Step.Database/Controllers/UsersController.cs b/Step.Database/Controllers/UsersController.cs index e460e1ad..5c721386 100644 --- a/Step.Database/Controllers/UsersController.cs +++ b/Step.Database/Controllers/UsersController.cs @@ -159,18 +159,27 @@ namespace Step.Database.Controllers public List GetMessageUserList() { - List userList = new List(); - - userList = dbCtx.Users.Select(x => new DTOMessageUserModel() + using (MachinesUsersController machineController = new MachinesUsersController()) { - Id = x.UserId, - FirstName = x.FirstName, - LastName = x.LastName, - Username = x.Username - }) - .ToList(); - return userList; + // Find user by Id with Role object included + var tmpUser = dbCtx + .Users + .Where(x => x.Deleted == false) // Get not deleted users + .Join(dbCtx.MachinesUsers,u=>u.UserId,m=>m.UserId, (u, m) => new { Users = u, MachinesUsers = m }) + .Where(x => x.MachinesUsers.Role.Level < MIN_CMS_ROLE) + .ToList(); + + return tmpUser + .Select(x => new DTOMessageUserModel() // Return DTOUserModel + { + Id = x.Users.UserId, + FirstName = x.Users.FirstName, + LastName = x.Users.LastName, + Username = x.Users.Username + }) + .ToList(); + } } #region User Manager @@ -179,7 +188,6 @@ namespace Step.Database.Controllers { using (MachinesUsersController machineController = new MachinesUsersController()) { - List roles = machineController.GetRolesList(); // Find user by Id with Role object included var tmpUser = dbCtx @@ -196,7 +204,8 @@ namespace Step.Database.Controllers LastName = x.LastName, Language = x.Language, Role = machineController.GetUserRoleData(MachineConfig.MachineId, x.UserId) - }) + }).Where( + x=> x.Role.Level < MIN_CMS_ROLE) .ToList(); } } @@ -229,6 +238,16 @@ namespace Step.Database.Controllers return GetUserInfo(userId); } + public Boolean isCMSRole(int roleId) + { + + var tmpRole = dbCtx.Roles.ToList().First(X => X.RoleId == roleId); + if (tmpRole == null) + return true; + else + return tmpRole.Level >= MIN_CMS_ROLE; + } + public DTOUserModel UpdateUserRole(int userId, int roleId) { using (MachinesUsersController machineController = new MachinesUsersController()) diff --git a/Step.Database/DatabaseContext.cs b/Step.Database/DatabaseContext.cs index d7805609..8e445abf 100644 --- a/Step.Database/DatabaseContext.cs +++ b/Step.Database/DatabaseContext.cs @@ -157,8 +157,13 @@ namespace Step.Database using (UsersController usersController = new UsersController()) { // Create default CMS user - usersController.CreateCmsDefaultUserIfNotExists(MachineConfig.MachineId, "cms", "cms", "cms", "cms", new CultureInfo("it"), ROLE_IDS.CMS_SERVICE_ONLY); - usersController.CreateCmsDefaultUserIfNotExists(MachineConfig.MachineId, "guest", "guest", "guest", "guest", new CultureInfo("it"), ROLE_IDS.GUEST); + usersController.CreateCmsDefaultUserIfNotExists(MachineConfig.MachineId, "cms.service", "cmsserviceonly", "cms", "service", new CultureInfo("it"), ROLE_IDS.CMS_SERVICE); + usersController.CreateCmsDefaultUserIfNotExists(MachineConfig.MachineId, "cms.ut", "cmsufficiotecnico", "cms", "ut", new CultureInfo("it"), ROLE_IDS.CMS_UT); + + // Create default CUSTOMER user + usersController.CreateCmsDefaultUserIfNotExists(MachineConfig.MachineId, "admin", "admin", "customer", "admin", Config.ServerConfig.ServerStartupConfig.Language, ROLE_IDS.CUSTOMER_ADMIN); + usersController.CreateCmsDefaultUserIfNotExists(MachineConfig.MachineId, "operator", "operator", "customer", "operator", Config.ServerConfig.ServerStartupConfig.Language, ROLE_IDS.CUSTOMER_OPERATOR); + usersController.CreateCmsDefaultUserIfNotExists(MachineConfig.MachineId, "mantainer", "mantainer", "customer", "mantainer", Config.ServerConfig.ServerStartupConfig.Language, ROLE_IDS.CUSTOMER_MANTAINER); } } else diff --git a/Step.Database/Migrations/Configuration.cs b/Step.Database/Migrations/Configuration.cs index e81afc8e..0d69855b 100644 --- a/Step.Database/Migrations/Configuration.cs +++ b/Step.Database/Migrations/Configuration.cs @@ -17,18 +17,21 @@ namespace Step.Database.Migrations protected override void Seed(DatabaseContext context) { - // This method will be called after migrating to the latest version. + // This method will be called after migrating to the latest version. 0-99 Customer. 100 - 199 CMS context.Roles.AddOrUpdate( - new RoleModel() { RoleId = (int)ROLE_IDS.CMS_SERVICE_ONLY, Level = 100, Name = "cmsServiceOnly" }, - new RoleModel() { RoleId = (int)ROLE_IDS.ADMIN, Level = 10, Name = "Admin" }, - new RoleModel() { RoleId = (int)ROLE_IDS.GUEST, Level = 1, Name = "Guest" } + new RoleModel() { RoleId = (int)ROLE_IDS.CMS_SERVICE, Level = 100, Name = "CMS Service department" }, + new RoleModel() { RoleId = (int)ROLE_IDS.CMS_UT, Level = 150, Name = "CMS Tecnical department" }, + + new RoleModel() { RoleId = (int)ROLE_IDS.CUSTOMER_ADMIN, Level = 30, Name = "Admin" }, + new RoleModel() { RoleId = (int)ROLE_IDS.CUSTOMER_OPERATOR, Level = 20, Name = "Operator" }, + new RoleModel() { RoleId = (int)ROLE_IDS.CUSTOMER_MANTAINER, Level = 10, Name = "Mantainer" } ); context.FunctionsAccess.AddOrUpdate( // General Function, if plcId is 0 then the functionality is not connected to the NC - new FunctionAccessModel() { Name = GENERAL, Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 100, ReadLevelMin = 1, PlcId = 0}, + new FunctionAccessModel() { Name = GENERAL, Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 0}, new FunctionAccessModel() { Name = USER_FUNCTIONS, Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 0}, - new FunctionAccessModel() { Name = NC_DATA, Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 10, ReadLevelMin = 1, PlcId = 0}, + new FunctionAccessModel() { Name = NC_DATA, Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 0}, new FunctionAccessModel() { Name = ALARM_CMD, Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 1}, new FunctionAccessModel() { Name = STARTUP_ICONS, Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 2}, @@ -40,7 +43,20 @@ namespace Step.Database.Migrations new FunctionAccessModel() { Name = AXES_SELECTION, Area = UNDER_HOOD, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 7}, new FunctionAccessModel() { Name = TOOL_MANAGER, Area = TOOLING_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 8}, - new FunctionAccessModel() { Name = MAINTENANCE, Area = MAINTENANCE_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 9} + new FunctionAccessModel() { Name = MAINTENANCE, Area = MAINTENANCE_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 9}, + + + + // Main Areas + new FunctionAccessModel() { Name = "productionArea", Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 20, ReadLevelMin = 1, PlcId = 0 }, + new FunctionAccessModel() { Name = "toolingArea", Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 20, ReadLevelMin = 1, PlcId = 0 }, + new FunctionAccessModel() { Name = "reportArea", Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 30, ReadLevelMin = 1, PlcId = 0 }, + new FunctionAccessModel() { Name = "alarmsArea", Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 0 }, + new FunctionAccessModel() { Name = "maintenanceArea", Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 0 }, + new FunctionAccessModel() { Name = "scadaArea", Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 0 }, + new FunctionAccessModel() { Name = "usersArea", Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 30, ReadLevelMin = 1, PlcId = 0 }, + new FunctionAccessModel() { Name = "jobeditorArea", Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 20, ReadLevelMin = 1, PlcId = 0 }, + new FunctionAccessModel() { Name = "utilitiesArea", Area = GENERAL_KEY, Enabled = true, WriteLevelMin = 1, ReadLevelMin = 1, PlcId = 0 } ); context.SaveChanges(); diff --git a/Step.Model/Constants.cs b/Step.Model/Constants.cs index 9c6fb291..66061f4f 100644 --- a/Step.Model/Constants.cs +++ b/Step.Model/Constants.cs @@ -17,13 +17,16 @@ namespace Step.Model BUTTON = 0, IMAGE = 1, INPUT = 2 - } - + } + + public const int MIN_CMS_ROLE = 100; public enum ROLE_IDS { - CMS_SERVICE_ONLY = 1, - ADMIN = 2, - GUEST = 3 + CMS_SERVICE = 1, + CMS_UT = 2, + CUSTOMER_ADMIN = 3, + CUSTOMER_OPERATOR = 4, + CUSTOMER_MANTAINER = 5 } public enum ACTIONS diff --git a/Step.Model/DTOModels/DTORoleModel.cs b/Step.Model/DTOModels/DTORoleModel.cs index 54f29811..8f623ae8 100644 --- a/Step.Model/DTOModels/DTORoleModel.cs +++ b/Step.Model/DTOModels/DTORoleModel.cs @@ -10,5 +10,6 @@ namespace Step.Model.DTOModels { public int Id; public string Name; + public int Level; } } diff --git a/Step/Controllers/WebApi/UserController.cs b/Step/Controllers/WebApi/UserController.cs index 0ff486b1..1309de5c 100644 --- a/Step/Controllers/WebApi/UserController.cs +++ b/Step/Controllers/WebApi/UserController.cs @@ -231,6 +231,10 @@ namespace Step.Controllers.WebApi { using (UsersController usersController = new UsersController()) { + + if(usersController.isCMSRole(roleId)) + return BadRequest("not_permitted"); + // Update database with new user's role var user = usersController.UpdateUserRole(userId, roleId); diff --git a/Step/wwwroot/src/@types/signalr.functions.d.ts b/Step/wwwroot/src/@types/signalr.functions.d.ts index 066769d5..d3a8560d 100644 --- a/Step/wwwroot/src/@types/signalr.functions.d.ts +++ b/Step/wwwroot/src/@types/signalr.functions.d.ts @@ -1,10 +1,10 @@ declare module signalr_security{ - interface securityFunction{ id: number, name: string, area: string, - enabled: boolean + enabled: boolean, + canRead: boolean, + canWrite: boolean } - } diff --git a/Step/wwwroot/src/services/hub.ts b/Step/wwwroot/src/services/hub.ts index 6b369598..24edba26 100644 --- a/Step/wwwroot/src/services/hub.ts +++ b/Step/wwwroot/src/services/hub.ts @@ -222,7 +222,7 @@ export class Hub { } private static functionalityData(status) { - machineStatusActions.setSecurityFunction(store, status); + machineStatusActions.updateSecurityFunction(store, status); } private static expiredMaintenances(status) { diff --git a/Step/wwwroot/src/services/loginService.ts b/Step/wwwroot/src/services/loginService.ts index d31139ba..281ad69b 100644 --- a/Step/wwwroot/src/services/loginService.ts +++ b/Step/wwwroot/src/services/loginService.ts @@ -1,7 +1,7 @@ import { baseRestService, AuthToken, to } from "src/_base/baseRestService"; import Factory from "src/_base/factoryService"; -import { store, appModelActions } from "src/store"; +import { store, appModelActions,machineStatusActions } from "src/store"; import { machineService } from "./machineService"; export class LoginService extends baseRestService { @@ -26,10 +26,18 @@ export class LoginService extends baseRestService { appModelActions.SetCurrentUser(store, null); }) appModelActions.SetCurrentUser(store, result); - + this.getAuthorizationFunction(); new machineService().getMachineCNInfo(); } + async getAuthorizationFunction(): Promise { + let result = await this.Get("api/authorization/functions", true).catch(() => { + appModelActions.SetCurrentUser(store, null); + }); + console.log("before2",result); + machineStatusActions.setSecurityFunction(store, result); + } + async getAllUsers(): Promise { let result = await this.Get("api/user/list",true); return result; diff --git a/Step/wwwroot/src/store/machineStatus.store.ts b/Step/wwwroot/src/store/machineStatus.store.ts index ee14345b..d5d544ad 100644 --- a/Step/wwwroot/src/store/machineStatus.store.ts +++ b/Step/wwwroot/src/store/machineStatus.store.ts @@ -84,6 +84,7 @@ export interface MachineStatusActions { isAreaVisible(context, areaname): boolean; setNcConnectionStatus(context, connected: boolean); setSecurityFunction(context, securityFunctions: Array); + updateSecurityFunction(context, securityFunctions: Array); setSoftKeyStatus(context, status: SoftKeyModel); setHeadsProperty(context, status: HeadsPropertyModel); setNcSoftKeyStatus(context, status); @@ -158,10 +159,15 @@ export const machineStatusStore = { }, mutations: { SetSecurityFunction(store, func: signalr_security.securityFunction) { - if (!store._functions.has(func.id) || store._functions.get(func.name).Enabled != func.enabled) { store._functions.set(func.name, func); store.functions = Array.from(store._functions.values()); - Factory.Get(MessageService).publishToChannel("force-ui-update"); + Factory.Get(MessageService).publishToChannel("force-ui-update"); + }, + UpdateSecurityFunction(store, func: signalr_security.securityFunction) { + if (!store._functions.has(func.id) || store._functions.get(func.name).Enabled != func.enabled) { + store._functions.get(func.name).Enabled = func.enabled; + store.functions = Array.from(store._functions.values()); + Factory.Get(MessageService).publishToChannel("force-ui-update"); } }, UpdateMachineStatus(store, model: MachineStatusModel) { @@ -254,6 +260,17 @@ export const machineStatusStore = { isAreaVisible(context, areaname): boolean { let inBrowser = (typeof cmsClient == "undefined"); let areaconfig = context.state.machineStatus.areasConfiguration; + let machconfig = context.state.machineStatus.functions; + let areaUserEnabled = false; + + for (const key in machconfig) { + if(machconfig.hasOwnProperty(key)){ + if(machconfig[key].name == areaname+"Area"){ + areaUserEnabled = machconfig[key].canWrite; + break; + } + } + } for (const key in areaconfig) { if (areaconfig.hasOwnProperty(key)) { @@ -261,8 +278,8 @@ export const machineStatusStore = { if (config && config.name && config.name == areaname) { - if (inBrowser) return config.allowExternalBrowser && config.enabled; - return config.enabled; + if (inBrowser) return config.allowExternalBrowser && config.enabled && areaUserEnabled; + return config.enabled && areaUserEnabled; } } } @@ -273,6 +290,11 @@ export const machineStatusStore = { context.commit("SetSecurityFunction", element); }); }, + updateSecurityFunction(context, securityFunctions: Array) { + securityFunctions.forEach(element => { + context.commit("UpdateSecurityFunction", element); + }); + }, setSoftKeyStatus(context, status: SoftKeyModel) { context.commit("SetSoftKeyStatus", status);