Asked by:
Need help on Custom AuthorizeAttribute implementation

Question
-
User1094269964 posted
HI Friends,
Need help on the below scenario for Custom AuthorizeAttribute implementation.
When the user login using Authentication/Login(FormCollection form) users roles will be fetched from database. See my code below but its not working
Lets say User1 logins to the application and we fetches his UserId,UserName and his roles.
Lets say his roles are "Admin,Developer,Tester" then he is allowed to call all the Action methods of AdminController,DeveloperController and TestController
But in case User1 has "Admin" role alone then he is allowed to call all the Action method of AdminController Only.
But in case User1 has "Developer" role alone then he is allowed to call all the Action method of DeveloperController Only.
How to do the above. Please help.
Below is my code and it is not working as per the above
namespace Sample.Controllers
{
public class AuthenticationController : Controller
{[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public void Login(FormCollection form)
{
UserSession userSession = UserSession.LoadUserSession(System.Web.HttpContext.Current.Session);
userSession.UserID = form["UserId"].ToUpper();
string url = "~/Authentication/NotAuthorized";
try
{
userSession.ValidateUser();
if(userSession.HasUserAuthenticated)
{
UserSession.SaveUserSession(System.Web.HttpContext.Current.Session, userSession);
url = "~/Home/Index";
}
}
catch(Exception ex)
{
throw ex;
}
this.Response.Redirect(url, false);
}[HttpGet]
public ActionResult NotAuthorized()
{
return View();
}
}public class AdminController :Controller
{
[HttpGet]
[CustomAuthorize(Roles.ADMIN)]
public ActionResult Index()
{
return View();
}[HttpPost]
[CustomAuthorize(Roles.ADMIN)]
public ActionResult Index(FormCollection collection)
{
return View();
}
}public class DeveloperController :Controller
{
[HttpGet]
[CustomAuthorize(Roles.ADMIN,Roles.DEVELOPER)]
public ActionResult Index()
{
return View();
}[HttpPost]
[CustomAuthorize(Roles.ADMIN, Roles.DEVELOPER)]
public ActionResult Index(FormCollection collection)
{
return View();
}
}public class TesterController :Controller
{
[HttpGet]
[CustomAuthorize(Roles.ADMIN, Roles.TESTER)]
public ActionResult Index()
{
return View();
}[HttpPost]
[CustomAuthorize(Roles.ADMIN, Roles.TESTER)]
public ActionResult Index(FormCollection collection)
{
return View();
}
}
}public class CustomAuthorize : AuthorizeAttribute
{
public readonly string[] AllowedRoles;
UserSession loggedInUser = null;public CustomAuthorize(params string[] roles)
{
this.AllowedRoles = roles;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
loggedInUser = UserSession.LoadUserSession(System.Web.HttpContext.Current.Session);
bool authorize = false;
if(loggedInUser.HasUserAuthenticated)
{
if(this.AllowedRoles.Count() > 0)
{
foreach (string role in this.AllowedRoles)
{
if (loggedInUser.UserRoles.Contains(role))
{
authorize = true;
}
}
}
authorize = true;
}
return authorize;
}protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if(loggedInUser.HasUserAuthenticated)
{
filterContext.Result = new RedirectResult("/Authentication/NotAuthorized");
}
else
{
filterContext.Result = new HttpUnauthorizedResult();
}
}}
public class UserSession
{
public string UserID { get; set; }
public string UserName { get; set; }
public List<string> UserRoles { get; set; }
public UserSession()
{
this.UserRoles = new List<string>();
}
public bool HasUserAuthenticated { get; set; }public void ValidateUser()
{
OracleParameter[] param = null;
param = new OracleParameter[] { new OracleParameter("UserId", this.UserID) };
OracleDataReader reader = DBHelper.ExecuteReader("select UserID,UserName,UserRoles from UserTable where UserId=:UserId", param);
while (reader.Read())
{
this.UserID = reader.GetString(0);
this.UserName = reader.GetString(1);
string roles = reader.GetString(2); //here we will get command separated string
foreach (string role in roles.Split(','))
{
this.UserRoles.Add(role);
}
}}
public static UserSession LoadUserSession(HttpSessionState state)
{
if (state["_userSession"] == null)
{
return new UserSession();
}
return state["_userSession"] as UserSession;
}public static void SaveUserSession(HttpSessionState state, UserSession session)
{
state["_userSession"] = state;
}
}public class DBHelper
{
public static OracleDataReader ExecuteReader(string query, OracleParameter[] param)
{
OracleConnection connection = new OracleConnection("somestring");
try
{
connection.Open();
OracleCommand cmd = new OracleCommand(query, connection);
foreach (var item in param)
{
cmd.Parameters.Add(item);
}
return cmd.ExecuteReader();}
catch
{
return null;
}
}
}public class SampleConstants
{
}
public static class Roles
{
public const string ADMIN = "Admin";
public const string DEVELOPER = "Developer";
public const string TESTER = "Tester";}
Saturday, June 20, 2020 4:52 PM
All replies
-
User475983607 posted
Please use the standard APIs rather than building your own if you are not familiar with writing a secure application.
This feature is built into the Identity API. Identity is a full featured security API with a data store.
If you do not wish to use Identity and have a custom data store, then you can implement the standard Authentication Cookie that comes with ASP.NET. All you have to do is set the user's roles/claims during login. The roles/claims are cached in the authentication cookie and the standard MVC [Authorize] attributes will function as expected.
https://stackoverflow.com/questions/31511386/owin-cookie-authentication-without-asp-net-identity
If you still wish to build customer security then I'm afraid you'll be on your own.
Saturday, June 20, 2020 6:18 PM -
User1094269964 posted
Thanks for the reponse. This is an existing application and we cannot change everything. But I need to fix the above scenario issue
Sunday, June 21, 2020 9:04 AM -
User475983607 posted
Thanks for the reponse. This is an existing application and we cannot change everything. But I need to fix the above scenario issue
I think the main issue is the ValidateUser method does not validate the user it tries to populate a UserSession object but never sets the HasUserAuthenticated property if validation is successful. At least I do not see the code. This is an easy bug to find if you were using the Visual Studio debugger.
There are other issues with the code and design. The UserTable is not normalized. It is a well known fact that denormalized tables in a relational database cause complex downstream code. The data access classes do not clean up connections or reader resources properly.
There is not much to change if you go with the OWIN Cookie Authentication. It a simple matter of replacing your code with the standard MVC libraries. the benefit is the standard libraries have been tested and are known to function properly.
Sunday, June 21, 2020 1:28 PM