Redo the permission system.

This commit is contained in:
Michael 2017-05-09 16:00:37 -04:00
parent cb653f021d
commit c84f619354
10 changed files with 125 additions and 233 deletions

View file

@ -9,6 +9,8 @@
using System.Web.Mvc.Html;
using System.Data.Entity;
using System.Text;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Security.Principal;
namespace Project_Unite
{
@ -226,9 +228,7 @@ public static bool CanSee(string userName, string fId)
if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(fId))
return false;
if (!Granted(userName, "CanPostTopics"))
return false; //obviously if this role has a global restraint for this ACL def we shouldn't let them post in ANY forum.
var db = new ApplicationDbContext();
var usr = db.Users.Include(x => x.Roles).FirstOrDefault(u => u.UserName == userName);
@ -282,7 +282,7 @@ public static bool CanReply(string userName, string fId)
if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(fId))
return false;
if (!Granted(userName, "CanPostTopics"))
if (HttpContext.Current.User.Identity.IsGuest())
return false; //obviously if this role has a global restraint for this ACL def we shouldn't let them post in ANY forum.
var db = new ApplicationDbContext();
@ -324,7 +324,7 @@ public static bool CanPost(string userName, string fId)
if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(fId))
return false;
if (!Granted(userName, "CanPostTopics"))
if (HttpContext.Current.User.Identity.IsGuest())
return false; //obviously if this role has a global restraint for this ACL def we shouldn't let them post in ANY forum.
var db = new ApplicationDbContext();
@ -389,7 +389,7 @@ public static bool CanManageRole(string userId, string roleId)
{
try
{
if (!Granted(userId, "CanEditRoles"))
if (!HttpContext.Current.User.Identity.IsAdmin())
return false;
var db = new ApplicationDbContext();
@ -425,40 +425,37 @@ public static ForumCategory GetForumById(string id)
}
public static bool Granted(string userName, string prop)
public static bool IsGuest(this IIdentity id)
{
if (string.IsNullOrWhiteSpace(prop))
return true;
try
{
var db = new ApplicationDbContext();
var usr = db.Users.FirstOrDefault(u => u.UserName == userName);
var userRoles = new List<Role>();
foreach (var usrRole in usr.Roles)
{
userRoles.Add(db.Roles.FirstOrDefault(r => r.Id == usrRole.RoleId) as Role);
}
db.Dispose();
var userRole = userRoles.OrderByDescending(m => m.Priority).First();
var t = userRole.GetType();
foreach (var propInf in t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
{
if (propInf.Name == prop && propInf.PropertyType == typeof(bool))
return (bool)propInf.GetValue(userRole);
}
if (HttpContext.Current.Request.IsAuthenticated)
return false;
}
catch (Exception ex)
{
Debug.Print(ex.ToString());
return false;
}
return true;
}
public static bool IsModerator(this IIdentity id)
{
var db = new ApplicationDbContext();
return db.Users.FirstOrDefault(x => x.UserName == id.Name).HighestRole.IsModerator;
}
public static bool IsDeveloper(this IIdentity id)
{
var db = new ApplicationDbContext();
return db.Users.FirstOrDefault(x => x.UserName == id.Name).HighestRole.IsDeveloper;
}
public static bool IsMember(this IIdentity id)
{
var db = new ApplicationDbContext();
return db.Users.FirstOrDefault(x => x.UserName == id.Name).HighestRole.IsMember;
}
public static bool IsAdmin(this IIdentity id)
{
var db = new ApplicationDbContext();
return db.Users.FirstOrDefault(x => x.UserName == id.Name).HighestRole.IsAdmin;
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Project_Unite
{
/// <summary>
/// Tells the Unite request router that this view/action requires administrative permissions.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class RequiresAdmin : Attribute
{
}
/// <summary>
/// Tells the Unite request router that this view/action requires developer permissions.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class RequiresDeveloper : Attribute
{
}
/// <summary>
/// Tells the Unite request router that this view/action requires moderator permissions.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class RequiresModerator : Attribute
{
}
}

View file

@ -21,10 +21,9 @@ public class AdminController : Controller
private ApplicationDbContext db = new ApplicationDbContext();
[Authorize]
[RequiresAdmin]
public ActionResult Index()
{
if (!ACL.Granted(User.Identity.Name, "CanAccessAdminCP"))
return new HttpStatusCodeResult(403);
return View();
}
}

View file

@ -130,12 +130,10 @@ public ActionResult ViewBlog(string id, string comment)
return View(blog);
}
[RequiresDeveloper]
[Authorize]
public ActionResult PostBlog()
{
if (!ACL.Granted(User.Identity.Name, "CanBlog"))
return new HttpStatusCodeResult(403);
var model = new PostBlogViewModel();
return View(model);
}

View file

@ -9,23 +9,19 @@
namespace Project_Unite.Controllers
{
[RequiresDeveloper]
[Authorize]
public class DeveloperController : Controller
{
// GET: Developer
public ActionResult Index()
{
if (!ACL.Granted(User.Identity.Name, "CanAccessDevCP"))
return new HttpStatusCodeResult(403);
ViewBag.Developer = true;
return View();
}
public ActionResult ToggleObsolete(string id)
{
if (!ACL.Granted(User.Identity.Name, "CanAccessDevCP"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var release = db.Downloads.FirstOrDefault(x => x.Id == id);
release.Obsolete = !release.Obsolete;
@ -35,9 +31,6 @@ public ActionResult ToggleObsolete(string id)
public ActionResult MakeUnstable(string id)
{
if (!ACL.Granted(User.Identity.Name, "CanAccessDevCP"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var release = db.Downloads.FirstOrDefault(x => x.Id == id);
release.IsStable = false;
@ -48,9 +41,6 @@ public ActionResult MakeUnstable(string id)
public ActionResult MakeStable(string id)
{
if (!ACL.Granted(User.Identity.Name, "CanAccessDevCP"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var release = db.Downloads.FirstOrDefault(x => x.Id == id);
release.IsStable = true;
@ -61,18 +51,12 @@ public ActionResult MakeStable(string id)
public ActionResult Releases()
{
if (!ACL.Granted(User.Identity.Name, "CanAccessDevCP"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
return View(db.Downloads);
}
public ActionResult AddRelease()
{
if (!ACL.Granted(User.Identity.Name, "CanAccessDevCP"))
return new HttpStatusCodeResult(403);
if (!ACL.Granted(User.Identity.Name, "CanReleaseBuild"))
return new HttpStatusCodeResult(403);
ViewBag.Developer = true;
var build = new PostDownloadViewModel();
@ -85,10 +69,6 @@ public ActionResult AddRelease()
[ValidateAntiForgeryToken]
public ActionResult AddRelease(PostDownloadViewModel model)
{
if (!ACL.Granted(User.Identity.Name, "CanAccessDevCP"))
return new HttpStatusCodeResult(403);
if (!ACL.Granted(User.Identity.Name, "CanReleaseBuild"))
return new HttpStatusCodeResult(403);
if (!ModelState.IsValid)
return View(model);
@ -174,8 +154,6 @@ public ActionResult AddRelease(PostDownloadViewModel model)
[Authorize]
public ActionResult Wiki()
{
if (!ACL.Granted(User.Identity.Name, "CanAccessDevCP"))
return new HttpStatusCodeResult(403);
ViewBag.Developer = true;
var db = new ApplicationDbContext();
var cats = db.WikiCategories;
@ -184,9 +162,6 @@ public ActionResult Wiki()
public ActionResult AddWikiCategory()
{
if (!ACL.Granted(User.Identity.Name, "CanAccessDevCP"))
return new HttpStatusCodeResult(403);
ViewBag.Developer = true;
var mdl = new AddWikiCategoryViewModel();
@ -198,8 +173,6 @@ public ActionResult AddWikiCategory()
[ValidateAntiForgeryToken]
public ActionResult AddWikiCategory(AddWikiCategoryViewModel model)
{
if (!ACL.Granted(User.Identity.Name, "CanAccessDevCP"))
return new HttpStatusCodeResult(403);
ViewBag.Developer = true;
if (!ModelState.IsValid)
return View(model);

View file

@ -131,16 +131,16 @@ public ActionResult EditPost(string id)
string acl_perm = "CanEditPosts";
if (topic == null)
return new HttpStatusCodeResult(404);
if (topic.AuthorId == User.Identity.GetUserId())
acl_perm = "CanEditOwnPosts";
if (!ACL.Granted(User.Identity.Name, acl_perm))
return new HttpStatusCodeResult(403);
if (topic.AuthorId != User.Identity.GetUserId())
if (!User.Identity.IsModerator())
return new HttpStatusCodeResult(403);
var model = new EditPostViewModel();
model.Id = topic.Id;
model.Contents = topic.Body;
return View(model);
}
[RequiresModerator]
[Authorize]
public ActionResult DeletePost(string id)
{
@ -150,10 +150,6 @@ public ActionResult DeletePost(string id)
string acl_perm = "CanDeletePosts";
if (topic == null)
return new HttpStatusCodeResult(404);
if (topic.AuthorId == User.Identity.GetUserId())
acl_perm = "CanDeleteOwnPosts";
if (!ACL.Granted(User.Identity.Name, acl_perm))
return new HttpStatusCodeResult(403);
var parent = db.ForumTopics.FirstOrDefault(x => x.Id == topic.Parent);
bool redirectToParent = false;
string cat = "";
@ -184,9 +180,8 @@ public ActionResult EditPost(EditPostViewModel model)
string acl_perm = "CanEditPosts";
if (topic == null)
return new HttpStatusCodeResult(404);
if (topic.AuthorId == User.Identity.GetUserId())
acl_perm = "CanEditOwnPosts";
if (!ACL.Granted(User.Identity.Name, acl_perm))
if (topic.AuthorId != User.Identity.GetUserId())
if (!User.Identity.IsModerator())
return new HttpStatusCodeResult(403);
var edit = new ForumPostEdit();
edit.EditedAt = DateTime.Now;

View file

@ -9,47 +9,33 @@
namespace Project_Unite.Controllers
{
[RequiresModerator]
[Authorize]
public class ModeratorController : Controller
{
// GET: Moderator
public ActionResult Index()
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
ViewBag.Moderator = true;
return View();
}
public ActionResult UserDetails(string id)
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var usr = db.Users.FirstOrDefault(x => x.DisplayName == id);
if (usr == null || !ACL.Granted(User.Identity.Name, "CanViewUserInfo"))
return new HttpStatusCodeResult(403);
if (usr == null)
return new HttpStatusCodeResult(404);
return View(usr);
}
public ActionResult Users()
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
if (!ACL.Granted(User.Identity.Name, "CanViewUserInfo"))
return new HttpStatusCodeResult(403);
return View(new ApplicationDbContext().Users);
}
public ActionResult Unban(string id, string returnUrl = "")
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
if (!ACL.Granted(User.Identity.Name, "CanIssueBan"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var usr = db.Users.FirstOrDefault(x => x.Id == id);
@ -73,10 +59,6 @@ public ActionResult Unban(string id, string returnUrl = "")
public ActionResult Ban(string id, string returnUrl = "")
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
if (!ACL.Granted(User.Identity.Name, "CanIssueBan"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var usr = db.Users.FirstOrDefault(x => x.Id == id);
@ -102,10 +84,6 @@ public ActionResult Ban(string id, string returnUrl = "")
public ActionResult Unmute(string id, string returnUrl = "")
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
if (!ACL.Granted(User.Identity.Name, "CanIssueMute"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var usr = db.Users.FirstOrDefault(x => x.Id == id);
@ -130,13 +108,6 @@ public ActionResult Unmute(string id, string returnUrl = "")
[ValidateAntiForgeryToken]
public ActionResult ChangeUserName(string id, ApplicationUser model, string returnUrl = "")
{
string acl_r = "CanEditUsernames";
if (id == User.Identity.GetUserId())
acl_r = "CanEditUsername";
if (!ACL.Granted(User.Identity.Name, acl_r))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var usr = db.Users.FirstOrDefault(x => x.Id == id);
if (usr == null)
@ -155,20 +126,12 @@ public ActionResult ChangeUserName(string id, ApplicationUser model, string retu
public ActionResult Lock(string id)
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var forum = db.ForumTopics.FirstOrDefault(x => x.Discriminator == id);
if (forum == null)
return new HttpStatusCodeResult(404);
string perm = "CanLockTopics";
var uid = User.Identity.GetUserId();
if (forum.AuthorId == uid)
perm = "CanLockOwnTopics";
if (!ACL.Granted(User.Identity.Name, perm))
return new HttpStatusCodeResult(403);
if (forum.IsLocked == true) //Save the DB queries...
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
@ -183,20 +146,12 @@ public ActionResult Lock(string id)
public ActionResult Unlock(string id)
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var forum = db.ForumTopics.FirstOrDefault(x => x.Discriminator == id);
if (forum == null)
return new HttpStatusCodeResult(404);
string perm = "CanUnlockTopics";
var uid = User.Identity.GetUserId();
if (forum.AuthorId == uid)
perm = "CanUnlockOwnTopics";
if (!ACL.Granted(User.Identity.Name, perm))
return new HttpStatusCodeResult(403);
if (forum.IsLocked == false) //Save the DB queries...
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
@ -212,20 +167,12 @@ public ActionResult Unlock(string id)
public ActionResult List(string id)
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var forum = db.ForumTopics.FirstOrDefault(x => x.Discriminator == id);
if (forum == null)
return new HttpStatusCodeResult(404);
string perm = "CanUnlistTopics";
var uid = User.Identity.GetUserId();
if (forum.AuthorId == uid)
perm = "CanUnlistOwnTopics";
if (!ACL.Granted(User.Identity.Name, perm))
return new HttpStatusCodeResult(403);
if (forum.IsUnlisted == false) //Save the DB queries...
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
@ -240,20 +187,12 @@ public ActionResult List(string id)
public ActionResult Unlist(string id)
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var forum = db.ForumTopics.FirstOrDefault(x => x.Discriminator == id);
if (forum == null)
return new HttpStatusCodeResult(404);
string perm = "CanUnlistTopics";
var uid = User.Identity.GetUserId();
if (forum.AuthorId == uid)
perm = "CanUnlistOwnTopics";
if (!ACL.Granted(User.Identity.Name, perm))
return new HttpStatusCodeResult(403);
if (forum.IsUnlisted == true) //Save the DB queries...
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
@ -280,9 +219,6 @@ public ActionResult Bans()
public ActionResult Logs()
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
return View(db.AuditLogs.Where(x => x.Level != AuditLogLevel.Admin));
@ -290,10 +226,6 @@ public ActionResult Logs()
public ActionResult Mute(string id, string returnUrl = "")
{
if (!ACL.Granted(User.Identity.Name, "CanAccessModCP"))
return new HttpStatusCodeResult(403);
if (!ACL.Granted(User.Identity.Name, "CanIssueMute"))
return new HttpStatusCodeResult(403);
var db = new ApplicationDbContext();
var usr = db.Users.FirstOrDefault(x => x.Id == id);

View file

@ -3,6 +3,7 @@
using System.Data.Entity.Migrations;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
@ -36,6 +37,44 @@ protected void Application_BeginRequest(object sender, EventArgs e)
migrator.Update();
string actionname = this.Request.RequestContext.RouteData.Values["action"].ToString();
string controllername = this.Request.RequestContext.RouteData.Values["controller"].ToString();
var asm = Assembly.GetExecutingAssembly();
var ctl = asm.GetTypes().FirstOrDefault(x => x.Name == controllername + "Controller");
var adm = ctl.GetCustomAttributes(false).Where(x => x is RequiresAdmin);
var mod = ctl.GetCustomAttributes(false).Where(x => x is RequiresModerator);
var dev = ctl.GetCustomAttributes(false).Where(x => x is RequiresDeveloper);
bool fail = false;
if (adm != null)
fail = !User.Identity.IsAdmin();
if (mod != null)
fail = !User.Identity.IsModerator();
if (dev != null)
fail = !User.Identity.IsDeveloper();
var act = ctl.GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(x => x.Name == actionname);
adm = act.GetCustomAttributes(false).Where(x => x is RequiresAdmin);
mod = act.GetCustomAttributes(false).Where(x => x is RequiresModerator);
dev = act.GetCustomAttributes(false).Where(x => x is RequiresDeveloper);
if (adm != null)
fail = fail || !User.Identity.IsAdmin();
if (mod != null)
fail = fail || !User.Identity.IsModerator();
if (dev != null)
fail = fail || !User.Identity.IsDeveloper();
if (fail == true)
{
string url = "http://" + this.Request.Url.Host.Replace("http://", "").Replace("https://", "") + "/Home/AccessDenied";
Response.Redirect(url, true);
return;
}
var addr = HttpContext.Current.Request.UserHostAddress;
var db = new ApplicationDbContext();
@ -47,6 +86,8 @@ protected void Application_BeginRequest(object sender, EventArgs e)
this.CompleteRequest();
return;
}
}
protected void Application_EndRequest(object s, EventArgs e)

View file

@ -243,6 +243,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ACL.cs" />
<Compile Include="ACLAttributes.cs" />
<Compile Include="App_Start\BundleConfig.cs" />
<Compile Include="App_Start\FilterConfig.cs" />
<Compile Include="App_Start\IdentityConfig.cs" />

View file

@ -97,9 +97,9 @@
}
<div class="container clearfix body-content">
<div class="panel panel-success">
<div class="panel panel-warning">
<div class="panel-body">
<p><span class="glyphicon glyphicon-exclamation-sign"></span> <strong>Welcome to Project: Unite!</strong> Things are a bit barren right now and not a lot of stuff is implemented - but feel free to explore!</p>
<p><span class="glyphicon glyphicon-warning-sign"></span> <strong>Do things seem broken?</strong> We are currently working on streamlining the permission system and its backend. Please be patient!</p>
</div>
</div>
@ -112,84 +112,8 @@
</div>
}
@if (ViewBag.Moderator == true)
{
<ul class="nav nav-tabs">
<li>@Html.ActionLink("Home", "Index", "Moderator")</li>
@if (ACL.Granted(User.Identity.Name, "CanIssueBan"))
{
<li>@Html.ActionLink("Bans", "Bans", "Moderator")</li>
}
@if (ACL.Granted(User.Identity.Name, "CanEditProfiles"))
{
<li>@Html.ActionLink("Users", "Users", "Moderator")</li>
}
<li>@Html.ActionLink("Audit logs", "Logs", "Moderator")</li>
</ul>
@RenderBody();
}
else if (ViewBag.Developer == true)
{
<ul class="nav nav-pills">
<li>@Html.ActionLink("Home", "Index", "Developer")</li>
<li>@Html.ActionLink("Releases", "Releases", "Developer")</li>
<li>@Html.ActionLink("Wiki", "Wiki", "Developer")</li>
<li>@Html.ActionLink("Bugs", "Bugs", "Developer")</li>
</ul>
@RenderBody();
}
else if (ACL.Granted(User.Identity.Name, ViewBag.ACLRule))
{
if (ViewBag.Admin == true)
{
if (ACL.Granted(User.Identity.Name, "CanAccessAdminCP"))
{
<ul class="nav nav-tabs">
<li>@Html.ActionLink("Home", "Index", "Admin")</li>
@if (ACL.Granted(User.Identity.Name, "CanEditRoles"))
{
<li>@Html.ActionLink("Roles", "Roles", "Admin")</li>
<li>@Html.ActionLink("Access Control", "AccessControl", "Admin")</li>
}
@if (ACL.Granted(User.Identity.Name, "CanEditProfiles"))
{
<li>@Html.ActionLink("Users", "Users", "Admin")</li>
}
@if (ACL.Granted(User.Identity.Name, "CanEditForumCategories"))
{
<li>@Html.ActionLink("Forum Categories", "Forums", "Admin")</li>
}
<li>@Html.ActionLink("Audit logs", "Logs", "Admin")</li>
</ul>
@RenderBody();
}
else
{
<h2>Access denied.</h2>
<p>You do not have permission to access this page. Contact an admin if this is in error.</p>
}
}
else
{
@RenderBody()
}
}
else
{
<h2>Access denied.</h2>
<p>You do not have permission to access this page. Contact an admin if this is in error.</p>
}<hr />
@RenderBody()
<hr />
</div>
@ -232,7 +156,7 @@
<p><strong>We'd like to formally thank Philip Adams.</strong> Without him, we would not exist. Phil has contributed years of work and help to ShiftOS and is the original developer of the game. He has written code that is still used to this day in modern ShiftOS, and much of the ideas and mechanics in the game are from his mind.</p>
<p>Check Phil out on YouTube: <a href="http://youtube.com/OSFirstTimer">OSFirstTimer</a> | <a href="https://www.youtube.com/user/AstralPhaser">AstralPhaser</a> | <a href="https://www.youtube.com/channel/UC2wLfbZrHQOxP2e5zkxYRjA">YouTube Millionaire</a></p>
@if (ACL.Granted(User.Identity.Name, "CanAccessAdminCP"))
@if (User.Identity.IsAdmin())
{
<p>@Html.ActionLink("Administrator Control Panel", "Index", "Admin")</p>}
</footer>