using System; using System.Collections.Generic; using System.Linq; using System.Web; using EnVisage.Code.Cache; using EnVisage.Models.Cache; using EnVisage.Code.BLL; using System.Web.Mvc; using Prevu.Core.Main; namespace EnVisage.Code { /// /// Manager for check security operations /// /// Created by SA public class SecurityManager { public class DefaultPageWithArea { public string Action; public string Controller; public Areas Area; public object Parameters; public DefaultPageWithArea(string action, string controller) { this.Action = action; this.Controller = controller; } public DefaultPageWithArea(string action, string controller, Areas area) { this.Action = action; this.Controller = controller; this.Area = area; } public DefaultPageWithArea(string action, string controller, Areas area, object parameters) { this.Action = action; this.Controller = controller; this.Area = area; this.Parameters = parameters; } } public static void tryLogin() { Controllers.AccountController a = new Controllers.AccountController(DependencyResolver.Current.GetService(), DependencyResolver.Current.GetService()); a.SSOLoginConfirmation(); } /// /// Returns current user Principal Id (GUID) /// public static Guid GetUserPrincipal() { string userIdAsText = HttpContext.Current.User.Identity.GetID(); Guid userId = new Guid(userIdAsText); return userId; } /// /// Returns true if passed Area is allowed to be accessed by passed Principal with desired Type of access /// public static bool CheckSecurityObjectPermission(Areas area, AccessLevel type) { try { List areas = new List {area}; return CheckAnySecurityObjectPermission(areas, type); } catch { } return false; } /// /// Returns true if any of passed Areas is allowed to be accessed by passed Principal with desired Type of access /// public static bool CheckAnySecurityObjectPermission(List areas, AccessLevel type) { var principalId = HttpContext.Current.User.Identity.GetID(); return CheckAnySecurityObjectPermissionForUser(areas, type, principalId); } private static bool CheckAnySecurityObjectPermissionForUser(List areas, AccessLevel type, string userId) { List stringAreas = new List(); if (areas != null && areas.Count > 0) areas.ForEach(a => stringAreas.Add(a.ToString())); if (userId == null || userId == Guid.Empty.ToString()) return false; SecurityAreasCache securityAreaCache = new SecurityAreasCache(); List s = new List(); foreach (var area in stringAreas) s.AddRange(securityAreaCache.Value.Where(x => x.PrincipalId == new Guid(userId) && x.SecurityObject == area)); if (s.Any()) { if (type == AccessLevel.Write) { return s.Any(x => x.Write == 1); } if (type == AccessLevel.Read) { return s.Any(x => (x.Read == 1 || x.Write == 1)); } } //var roles = user.AspNetRoles.Select(x => new Guid(x.Id)); var roles = new UsersCache().Value.FirstOrDefault(x => x.Id == new Guid(userId)).Roles; s = new List(); foreach (var role in roles) { foreach (var area in stringAreas) s.AddRange(securityAreaCache.Value.Where(x => x.PrincipalId == role && x.SecurityObject == area)); } if (s.Any()) { if (type == AccessLevel.Write) return s.Any(x => x.Write == 1); if (type == AccessLevel.Read) return s.Any(x => (x.Read == 1 || x.Write == 1)); } return false; } public static bool CheckProjectPermission(Guid ProjectId, AccessLevel Type) { var PrincipalId = HttpContext.Current.User.Identity.GetID(); if (PrincipalId == null || ProjectId == null || PrincipalId == Guid.Empty.ToString()) return false; var userId = new Guid(PrincipalId); EnVisageEntities dbContext = new EnVisageEntities(); var accessGranted=CheckProjectPermission(userId, ProjectId, Type, dbContext); //EnVisageEntities dbContext = new EnVisageEntities(); //bool accessGranted = dbContext.VW_ProjectAccessByUserExtended.Where(x => // x.UserId.Equals(userId) && // x.Id.Equals(ProjectId) && // (((Type == AccessLevel.Read) && ((x.Read.HasValue && (x.Read.Value == 1)) || (x.Write.HasValue && (x.Write.Value == 1)))) || // ((Type == AccessLevel.Write) && x.Write.HasValue && (x.Write == 1)))).Any(); //if (!accessGranted) //{ // ProjectManager prMngr = new ProjectManager(dbContext); // var projectsByAllocations = prMngr.GetAssignedProjectsByUserId(new Guid(PrincipalId)); // accessGranted = (projectsByAllocations != null) && (projectsByAllocations.Contains(ProjectId)); //} return accessGranted; } public static bool CheckProjectPermission(Guid userId, Guid ProjectId, AccessLevel Type, EnVisageEntities dbContext) { bool accessGranted = dbContext.VW_ProjectAccessByUserExtended.Where(x => x.UserId.Equals(userId) && x.Id.Equals(ProjectId) && (((Type == AccessLevel.Read) && ((x.Read.HasValue && (x.Read.Value == 1)) || (x.Write.HasValue && (x.Write.Value == 1)))) || ((Type == AccessLevel.Write) && x.Write.HasValue && (x.Write == 1)))).Any(); if (!accessGranted) { ProjectManager prMngr = new ProjectManager(dbContext); var projectsByAllocations = prMngr.GetAssignedProjectsByUserId(userId); accessGranted = (projectsByAllocations != null) && (projectsByAllocations.Contains(ProjectId)); } return accessGranted; } public static bool CheckScenarioPermission(Guid ScenarioId, AccessLevel Type) { // Get parent project (part) id for this scenario EnVisageEntities dbContext = new EnVisageEntities(); var scenMngr = new ScenarioManager(dbContext); Scenario scenario = scenMngr.GetScenario(ScenarioId); if ((scenario != null) && scenario.ParentId.HasValue) { Guid projectId = scenario.ParentId.Value; return CheckProjectPermission(projectId, Type); } return false; } /// /// Gets a dictionary of teams which user has access to. Key=, Value=. /// Method returns data from database view VW_User2Team. If it returns more than one record for tuple [UserId, TeamId] (should not) /// then method returns Max of provided values. /// /// Database context. /// User.Id /// A list of Team.Id values to filter by. /// public static Dictionary GetTeamPermissionsForUser(EnVisageEntities dbContext, string userId, List teamsFilter) { var teamManager = new TeamManager(dbContext); var teams = teamManager.GetTeamsByUserFiltered(userId, teamsFilter, null, null); return teams.GroupBy(t => t.TeamId).ToDictionary(gr => gr.Key, el => el.Max(t => t.AccessLevel)); } /// /// Returns first available Default Page for user depending on his security settings. Returnable Item format: Action, Controller /// public static DefaultPageWithArea RedirectToDefaultPage(string userId) { if (SecurityManager.IsResourceOnlyAccess(userId)) { var mngr = new Code.BLL.AccountManager(new EnVisageEntities()); var resourceId = mngr.GetCurrentResourceId(userId); if (resourceId.HasValue) { return new DefaultPageWithArea("Details", "PeopleResource", Areas.PeopleResourceDetails, new { resourceId = resourceId.Value.ToString() }); } } else { foreach (DefaultPageWithArea page in GetDefaultPages()) { if (CheckAnySecurityObjectPermissionForUser(new List() { page.Area }, AccessLevel.Read, userId)) { return new DefaultPageWithArea(page.Action, page.Controller); } } } return new DefaultPageWithArea("AccessDenied", "Home");// this should always end with some landing page accessible by all users to prevent possible infinite cycles in client code } /// /// Indicates that current user has access only to Resource Details page. /// This way system should redirect him to the related page and deny access to all other areas. /// /// True - if user has access only to resource details, otherwise - false. public static bool IsResourceOnlyAccess(string userId) { var resourceDetailsGroupPermissions = new string[] { Areas.PeopleResourceDetails.ToString(), Areas.RD_ResourceInformation.ToString(), Areas.RD_ResourceNonProjectTime.ToString(), Areas.RD_ResourceNPTAllocationCategory.ToString(), Areas.RD_ResourceSkills.ToString(), Areas.RD_ResourceTimeAllocation.ToString(), Areas.RD_ResourceTimeAllocationActual.ToString(), Areas.RD_ResourceTimeAllocationProjected.ToString() }; SecurityAreasCache securityAreaCache = new SecurityAreasCache(); var roles = new UsersCache().Value.FirstOrDefault(x => x.Id == new Guid(userId)).Roles; // get all areas user has access to var userAccessAreas = securityAreaCache.Value.Where(t => t.PrincipalId == new Guid(userId)); var roleAccessAreas = securityAreaCache.Value.Where(t => roles.Contains(t.PrincipalId)); var permissions = new Dictionary(); foreach (var item in roleAccessAreas) { if (!permissions.ContainsKey(item.SecurityObject)) { if (item.Write == 1) permissions.Add(item.SecurityObject, AccessLevel.Write); else if (item.Read == 1) permissions.Add(item.SecurityObject, AccessLevel.Read); } else { if (item.Write == 1) permissions[item.SecurityObject] = AccessLevel.Write; else if (item.Read == 1) permissions[item.SecurityObject] = AccessLevel.Read; } } foreach (var item in userAccessAreas) { if (!permissions.ContainsKey(item.SecurityObject)) { if (item.Write == 1) permissions.Add(item.SecurityObject, AccessLevel.Write); else if (item.Read == 1) permissions.Add(item.SecurityObject, AccessLevel.Read); } else { if (item.Write == 1) permissions[item.SecurityObject] = AccessLevel.Write; else if (item.Read == 1) permissions[item.SecurityObject] = AccessLevel.Read; else if (item.Read == 0 && item.Write == 0) permissions.Remove(item.SecurityObject); } } // get user permissions other than resource details var additionalAreas = permissions.Keys.Except(resourceDetailsGroupPermissions); return !additionalAreas.Any(); } /// /// Checks if specific default page is accessible by current user /// /// An ID of the current User /// Name of the action method of the default page /// Name of the controller of the default page public static bool IsDefaultPageAvailable(string userId, string action, string controller) { List allPages = GetDefaultPages(); if (!allPages.Exists(p => p.Action.Equals(action, StringComparison.InvariantCultureIgnoreCase) && p.Controller.Equals(controller, StringComparison.InvariantCultureIgnoreCase))) throw new ArgumentException(string.Format("There is no default page registered for given action ({0}) and controller ({1}) - check the GetDefaultPages method", action, controller)); DefaultPageWithArea page = allPages.First(p => p.Action.Equals(action, StringComparison.InvariantCultureIgnoreCase) && p.Controller.Equals(controller, StringComparison.InvariantCultureIgnoreCase)); return CheckAnySecurityObjectPermissionForUser(new List() { page.Area }, AccessLevel.Read, userId); } /// /// Returns a list of all system default landing pages users should go to upon login depending on their permissions. Item format: Action, Controller, required Security Area permission (can be null - means everyone has access) /// /// private static List GetDefaultPages() { List pages = new List(); pages.Add(new DefaultPageWithArea("Index", "Home", Areas.Dashboard)); pages.Add(new DefaultPageWithArea("Index", "Project", Areas.Projects)); pages.Add(new DefaultPageWithArea("ImportActuals", "Project", Areas.ImportActuals)); pages.Add(new DefaultPageWithArea("Details", "PeopleResource", Areas.PeopleResourceDetails)); return pages; } } }