0

I am trying to use Aspnet with Roles. With the NRE, still I cannot figure out what to instantiate. This is in the controller

[Authorize(Roles = "Admin")]
public ActionResult ForAdmin()
{
    return View();
}

This is how I authorize

public Programmer GetLoginCredentials(Login credential)
{
    Programmer programmer = null;
    HttpContext.Current.Session["ProgrammerName"] = null;
    HttpContext.Current.Session["Roles"] = null;
    using (
        var cmd = new SqlCommand("Sp_GetLoginCredentials", _dbConnection)
        {
            CommandType = CommandType.StoredProcedure
        })
    {
        try
        {
            cmd.Parameters.AddWithValue("@Username", credential.Username);
            cmd.Parameters.AddWithValue("@Password", credential.Password);
            var da = new SqlDataAdapter(cmd);
            var ds = new DataSet();
            da.Fill(ds);

            if (ds.Tables[0].Rows.Count <= 0) return null;
            foreach (DataRow row in ds.Tables[0].Rows)
            {
                programmer = new Programmer()
                {
                    ProgrammerId = Convert.ToInt32(row["ProgrammerId"]),
                    ProgrammerName = row["ProgrammerName"].ToString(),
                    Username = row["Username"].ToString(),
                    Password = row["Password"].ToString()
                };

                HttpContext.Current.Session["ProgrammerName"] = programmer.ProgrammerName;
            }
            if (programmer != null)
            {
                GetRoles(programmer);
            }

            return programmer;
        }
        catch
        {
            return null;
        }
    }
}

This is how I fill the session with roles

public List<Role> GetRoles(Programmer credential)
{
    var roleList = new List<Role>();
    using (var cmd = new SqlCommand("Sp_GetRoles", _dbConnection) {CommandType = CommandType.StoredProcedure})
    {
        cmd.Parameters.AddWithValue("@Username", credential.Username);
        cmd.Parameters.AddWithValue("@Password", credential.Password);

        var da = new SqlDataAdapter(cmd);
        var ds = new DataSet();
        da.Fill(ds);

        if (ds.Tables[0].Rows.Count > 0)
        {
            roleList.AddRange(from DataRow row in ds.Tables[0].Rows
                select new Role()
                {
                    RoleName = row["RoleName"].ToString()
                });
        }
        HttpContext.Current.Session["Roles"] = roleList;
    }
    return roleList;
}

This is my role provider

public class SiteRole : RoleProvider
{
    public override string[] GetRolesForUser(string username)
    {
        var data = HttpContext.Current.Session["Roles"];
        return data as string[];
    }
}

In my Session["Roles"] I get it like this enter image description here

So that means I am able to get the "Admin" role but in my browser, I get this error:

[NullReferenceException: Object reference not set to an instance of an object.]
   System.Web.Security.RolePrincipal.IsInRole(String role) +9803940
   System.Linq.Enumerable.Any(IEnumerable`1 source, Func`2 predicate) +146
   System.Web.Mvc.AuthorizeAttribute.AuthorizeCore(HttpContextBase httpContext) +333
   System.Web.Mvc.AuthorizeAttribute.OnAuthorization(AuthorizationContext filterContext) +379
   System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor) +143
   System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__19(AsyncCallback asyncCallback, Object asyncState) +1680
   System.Web.Mvc.Async.WrappedAsyncResult`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +59
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
   System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate`1 endDelegate, Object tag, Int32 timeout) +94
   System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +559
   System.Web.Mvc.Controller.<BeginExecuteCore>b__1c(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState) +82
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +73
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
   System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext) +105
   System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +588
   System.Web.Mvc.Controller.<BeginExecute>b__14(AsyncCallback asyncCallback, Object callbackState, Controller controller) +47
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +65
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
   System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext) +139
   System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +484
   System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +50
   System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState) +98
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +73
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +151
   System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext) +106
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +446
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +88
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +50
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +103
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

Can you please show me where I am getting it wrong? Thank you.

stack questions
  • 862
  • 2
  • 15
  • 29
  • I recommend against mixing authorization state and session state. Most authentication / authorization frameworks already have built in mechanisms for persisting roles and retrieving them based on the authentication token. Use those and do not try to store this information in the session state where it does not belong. If you want additional help you should provide the details for your authentication setup. – Igor Nov 01 '17 at 10:46
  • 1
    Possible duplicate of [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Igor Nov 01 '17 at 10:49
  • Thank you Igor. I will change my code to reflect what you advised. Is there a way to change the signature of "public override string[] GetRolesForUser(string username)" so that it will receive 2 parameters to string username and string password? – stack questions Nov 01 '17 at 10:53
  • No but password should only ever be used once by the user when authentication. This is authorization, a check that should occur after authentication, so password should no longer be passed around or used. – Igor Nov 01 '17 at 10:55
  • What authentication / authorization framework are you using? If you are trying to create your own I would advise against it, there are plenty of very good and secure out of the box solutions like [asp.net-identity](https://www.asp.net/identity). – Igor Nov 01 '17 at 10:55
  • Oh I see. Okay. I'll change my Code to make it right. The suggestion of Anderson Pimentel made my code to work. But still I will do your suggestion @Igor. – stack questions Nov 01 '17 at 10:57
  • I updated my code to reflect how I authorize @Igor – stack questions Nov 01 '17 at 10:59
  • This is why an existing framework is a good idea. One potential big security hole is storing passwords as plain text. The other is using the session state for authorization. Check out some of the existing frameworks. If you are using visual studio there is a boiler plate template for MVC project with same basic pages including authentication/authorization using asp.net identity. That can give you a sample running app to see how it is configured and how it works. If you get stuck come back and ask a question on [so]. Good luck! – Igor Nov 01 '17 at 11:04

1 Answers1

1

You cannot cast HttpContext.Current.Session["Roles"] to string[] because it's of type List<Role>

Try this instead:

public override string[] GetRolesForUser(string username)
{
    var data = HttpContext.Current.Session["Roles"] as IEnumerable<Role>;
    return data.Select(d => d.RoleName).ToArray();
}
Igor
  • 60,821
  • 10
  • 100
  • 175
Anderson Pimentel
  • 5,086
  • 2
  • 32
  • 54