0

I am trying to learn basic security and access limitations on ASP MVC.

So far, i have read/watched tutorials but all of them seems different from one another. If i will search something, it will lead me to another implementation which is totally different from what i have.

I implemented Authentication and custom role provider and i have some questions regarding how things work. Majority of explanations that i found from the internet seems overly complicated or outdated.

This is how i implemented my authentication.

login controller:

 [HttpGet]
    [ActionName("login")]
    public ActionResult login_load()
    {
        return View();
    }

    [HttpPost]
    [ActionName("login")]
    public ActionResult login_post(string uname,string pword)
    {
        using (EmployeeContext emp = new EmployeeContext())
        {
            int success = emp.login.Where(x => x.username == uname && x.password == pword).Count();
            if (success == 1)
            {
                FormsAuthentication.SetAuthCookie(uname, false);

                return RedirectToAction("Details", "Enrollment");
            }
            return View();
        }
    }

Then i protected most of my controllers with [Authorize]

Question #1 What's the purpose of FormsAuthentication.SetAuthCookie(uname, false); and what should i typicalfly use it for? would it be alright to store the username. Do i need it for comparison later on?(further security?). It says here that Authentication ticket will be given to the username. Are those the ones with random letters?

--

After that, i decided to dive deeper and implemented a custom role provider

from roleprovider.cs(I only implemented 2 methods so far)

public override string[] GetRolesForUser(string username)
            {
                if (!HttpContext.Current.User.Identity.IsAuthenticated)
                {
                    return null;
                }

                var cacheKey = username;
                if (HttpRuntime.Cache[cacheKey] != null)
                {
                    return (string[])HttpRuntime.Cache[cacheKey];
                }
                string[] roles = new string[] { };
                using (MvcApplication6.Models.EmployeeContext emp = new MvcApplication6.Models.EmployeeContext())
                {
                    roles = (from a in emp.login
                             join b in emp.roles on a.role equals b.id
                             where a.username.Equals(username)
                             select b.role).ToArray<string>();
                    if (roles.Count() > 0)
                    {
                        HttpRuntime.Cache.Insert(cacheKey, roles, null, DateTime.Now.AddMinutes(_cacheTimeoutInMinute), Cache.NoSlidingExpiration);
                    }
                }
                return roles;
            }

Question #2 I am kinda confused here and i need a deep clarification: so what is basically the purpose of the cacheKey and from my example, i just made it equal to uname since i have no idea what's going on.

Question #3 Why is it returned (string[])HttpRuntime.Cache[cacheKey]; if the value is null? when is it returned and who is receiving it?

Question #4 After getting the value the list of roles from the database, this function will be called HttpRuntime.Cache.Insert(cacheKey, roles, null, DateTime.Now.AddMinutes(_cacheTimeoutInMinute), Cache.NoSlidingExpiration);. So from what i see, the roles are being inserted into the cache? is it for checking the login type later on?

Question #5

from this lines of code:

  public override bool IsUserInRole(string uname, string roleName)
            {
                var userRoles = GetRolesForUser(uname);
                return userRoles.Contains(roleName);
            }

When are they exactly triggered and who provides the parameters? is the roleName from the cache?

I am having a hard time visualizing what's happening under the hood. Explanations/Referrals will be very helpful.

Carlos Miguel Colanta
  • 2,685
  • 3
  • 31
  • 49
  • I also would like to add, do i need to implement `Authentication` before `Role Providers` ? I feel like `RP` gets triggered after the user successfully logged in. – Carlos Miguel Colanta Sep 06 '15 at 20:35

1 Answers1

1

What's the purpose of FormsAuthentication.SetAuthCookie()?

This is ASP.NET FormsAuthentication's built-in method for dealing with authentication cookies.

Basically, it's doing the hard work for you; creating a cookie for a specific user, giving it to them and then using it to recognise the same user in the future. You want to use this function to log a user in (if they enter correct credentials).

The string parameter is for a username. Yes, you can use username.

The bool parameter is for if you want the cookie to be persistent. That is, keep them logged in even if they close the browser (whether or not to use a session).

By using FormsAuthentication in this way, ASP.NET will automatically detect the user again when they visit subsequent pages.

What is basically the purpose of the cacheKey?

The Cache component of the HttpRuntime is for managing a "box" of objects that you might retrieve frequently but don't want to be hitting the database all the time for.

The Cache is implemented as a kind of Key-Value Pair. The cacheKey in your example is a key in the Key-Value collection. You can think of it like other similar data structures used in other languages.

{
    "carlobrew": {
        "roles": {
            "Name": "Administrator"
        }
    }
}

So you're basically "saving" the roles of the user carlobrew in a container so that you can get them again later. The key in a Key-Value Pair is used to refer back to the data that you put in there. The key you are using to refer back to the saved information is the uname; that is, the username.

The key in Key-Value Pairs is unique, so you cannot have two keys called carlobrew.

Why is it returned (string[])HttpRuntime.Cache[cacheKey]; if the value is null?

There are two steps to using a typical "cache box" like this.

  1. If we find the key (such as the user carlobrew) then we can simply return the data straight away. It's not if the value is null. It's if the value is not null. That's why the code is if (HttpRuntime.Cache[cacheKey] != null).
  2. If the key cannot be found (that is, we don't have the key for carlobrew), well then we have to add it ourselves, and then return it.

Since it's a cache, ASP.NET MVC will automatically delete things from the cache when the timer expires. That's why you need to check to see if the data is null, and re-create it if it is.

The "who is receiving it" is whichever object is responsible for calling the GetRolesForUser() method in the first place.

So from what i see, the roles are being inserted into the cache?

Yes.

Basically, if the data isn't in the cache, we need to grab it from the database and put it in there ourselves, so we can easily get it back if we call the same method soon.

Let's break it down. We have:

Insert(cacheKey, roles, null, DateTime.Now.AddMinutes(_cacheTimeoutInMinute), Cache.NoSlidingExpiration);
  • Insert is the method. We're calling this.
  • cacheKey is the key part of the Key-Value Pair. The username.
  • roles is the object that we want to store in cache. The object can be anything we want.
  • DateTime.Now.AddMinutes(_cacheTimeoutInMinute) is telling ASP.NET MVC when we want this data to expire. It can be any amount of time that we want. I'm not sure what the variable _cacheTimeoutInMinute maybe it's 5 or 15 minutes.
  • Cache.NoSlidingExpiration is a special flag. We're telling ASP.NET that, when we access this data, don't reset the expiration timer back to its full. For example, if our timer was 15 mins, and the timer was about to expire with 1 minute to go, if we were using a sliding expiration and tried to access the data, the timer would reset back to 15 minutes and not expire the data.

Not sure what you mean by "is it for checking the login type later on". But no, there isn't any checking of login type here.

IsUserInRole

You would probably call this when the user is trying to do something. For example, if the user goes to /Admin/Index page, then you could check to see if the user is in the Administrator role. If they aren't, you'd return a 401 Unauthorized response and tell you the user they aren't allowed to access that page.

public Controller Admin
{
    public ActionResult Index()
    {
        if (!IsUserInRole("Administrator"))
        {
            // redirect "not allowed"
        }

        return View();
    }
}
Rowan Freeman
  • 15,724
  • 11
  • 69
  • 100