Thursday, March 2, 2017

Authentication and authorization in ASP.NET MVC. Custom authorize attribute

Authentication and authorization are very important functions, unlikely some serious web-service can live without it. Let's consider the Details of these two concepts.

 

Authorization is the function of specifying access rights to resources related to information security and computer security in general and to access control in particular. More formally, "to authorize" is to define an access policy. For example, human resources staff is normally authorized to access employee records and this policy is usually formalized as access control rules in a computer system. During operation, the system uses the access control rules to decide whether access requests from (authenticated) consumers shall be approved (granted) or disapproved (rejected). Resources include individual files or an item's datacomputer programs, computer devices and functionality provided by computer applications. Examples of consumers are computer users, computer programs and other devices on the computer.

 

Authentication  is the act of confirming the truth of an attribute of a single piece of data (datum) or entity. In contrast with identification which refers to the act of stating or otherwise indicating a claim purportedly attesting to a person or thing's identity, authentication is the process of actually confirming that identity. It might involve confirming the identity of a person by validating their identity documents, verifying the validity of a Website with a digital certificate, tracing the age of an artifact by carbon dating or ensuring that a product is what its packaging and labeling claim to be. In other words, authentication often involves verifying the validity of at least one form of identification.

 

I don`t want to pay your attention on great scope of theory, I think it`s not necessary, so let`s see something more practice.

 

As for me – I`m using my own custom authorize attribute. Why? – Because, default  [Authorize] from Microsoft sometimes can sign out user without any reason, although, on localhost it worked correctly. The second reason is that the default set User-Roles is difficult to integrate in my database.

 

The program is simple, user need to enter his login data. After that system needs to find an object of user using these data. If object is null system returns an error like this “The login or password is wrong”, but if the object is not null, system needs to save some data in cookies, to read it in future and authorize user without entering login and password.

 

Usually,  I encrypt login(email), it is not the best way and I agree with you it is a serious bag in security. However I think for some small projects it can be allowed.

 

What attribute needs to do? – It needs to read data from cookies, decrypt it, find user in DB and authorize him.

 

The structure of database(DB)

Pic. 1. Structure of DB. User-Role

 

There are 3 tables in our DB. There are: User – for taking users data, Role – list of roles, and UserRole that takes linking of some user with some role. As you see one user can have more than one role (security level).

 

The program

 

The code of custom attribute

 

    public class AuthenticateAttribute : AuthorizeAttribute

    {

        DataManager dm = new DataManager();

        public bool AllowAnonymus { get; set; }

 

        public AuthenticateAttribute() { }

 

        protected override bool AuthorizeCore(HttpContextBase httpContext)

        {

            if (AllowAnonymus)

                return true;

            User user = FormsAuthenticationService.User;

            if (user != null)

                if (base.Roles == null)

                    return true;

                else

                    return user.IsInRole(base.Roles);

            return false;

        }

 

        protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)

        {

            filterContext.Result = new System.Web.Mvc.RedirectResult("/Account/Login/?ReturnUrl=" + filterContext.HttpContext.Request.Url.AbsolutePath);

        }

    }

 

 

 

To create a custom attribute we need to inherit from AuthorizeAttribute (default class from Microsoft) and override AuthorizeCore function, which work with this algorithm: if function has a AllowAnonymus parameter it should return true (which means access is permitted); if AuthorizeCore has no parameters we should create an object of user from another function (see below), if this object is equal to null that means that user entered incorrect data so return false; if user (object) is not null, it means that data is correct, consequently, function asking base parameter (base.Roles). If it equals null, it returns true (it means that all roles can access) otherwise we need to ensure that user has a role that is requested (IsInRole() function)

 

HandleUnauthorizedRequest it is override function that runs when users request some secured action or data. This means next: when unauthorized user tries to access some data this function redirect him/her to this page

/Account/Login/?ReturnUrl=" + filterContext.HttpContext.Request.Url.AbsolutePath

/Account/Login/ - this is a login page

/?ReturnUrl=" + filterContext.HttpContext.Request.Url.AbsolutePath – parameter which has a path of  page user try to access and after authorization we should redirect him to this page.

 

Let`s take a look at FormsAuthenticationService class occurring checking on user-role linking and reading cookies

 

  public class FormsAuthenticationService

    {

        public const string AuthCookieName = "_data";   //назва кукі

 

        public static void Login(User user)

        {

            DateTime expiresDate = DateTime.Now.AddMinutes(30);

            if (rememberMe)

                expiresDate = expiresDate.AddMonths(1);

            SetValue(AuthCookieName, user.Email, expiresDate);

        }

 

        public static User User        

         {

            get

            {

                DataManager dm = new DataManager();

                User user = null;

                object cookie = HttpContext.Current.Request.Cookies[AuthCookieName] != null ?HttpContext.Current.Request.Cookies[AuthCookieName].Value : null;

                if (cookie != null && !string.IsNullOrEmpty(cookie.ToString()))

                {

                    try

                    {

                        //розшифровуємо кукі

                        string email = StringCipher.Decrypt(cookie.ToString());

                        user = dm.GetUsers().FirstOrDefault(u => u.Email == email);

                    }

                    catch

                    {

                        return user;

                    }

                }

                return user;

            }

        }

 

        public static void Logout() //виходимо

        {

            var cookies = new HttpCookie(AuthCookieName);

            cookies.Value = "Slava Ukraini";

            cookies.Expires = DateTime.Now.AddMonths(1);

            HttpContext.Current.Response.Cookies.Add(cookies);

 

        }

        //ставимо кукі шуфруючи StringCipher.Encrypt(cookieObject)

        private static void SetValue(string cookieName, string cookieObject, DateTime dateStoreTo)

        {

            HttpCookie userCookie = new HttpCookie(AuthCookieName, StringCipher.Encrypt(cookieObject));

            userCookie.Expires = dateStoreTo;

            HttpContext.Current.Response.SetCookie(userCookie);

        }

 

 

 

The authorization is implemented with Login function, it takes the value of the user object. To log out  is used function Logout(). These two functions use SetValue() function which write data in cookies. In the case of sing in it writes an encrypted or hashed login (I also recommend to encrypt a password). In the case of log out it rewrites login data to  “Slava Ukraini”, as you  see the algorithm can`t access using such combination of words.

 

The main feature of this class is the User field, which returns an object of the user that is authorized. To do this it reads the cookies than decrypts it and finds the object of user in DB. If it finds one of the methods returns it (the object) otherwise it returns null.

 

As you see, it is very simple. Although in your own sites try to do something more secure. I'm using user's email, encrypt it and writing in cookies it is not the best way in the case of secure data, remember it is just an example.

 

Another one function I want to talk about is IsInRole(). It takes only one parameter, it is a string, which contains the list of roles and when the user has one of this role  the system get access to it. The roles can be set with no limits or some grammar rules.

        public bool IsInRole(string Roles)         

  {

            foreach (var r in FormsAuthenticationService.User.Roles)

                if (Roles.Contains(r.Code))

                    return true;

            return false;

        }

 

FormsAuthenticationService.User.Roles it is a class generated with Entity framework for UserRole table of our DB. It`s field returns a list of all roles that is link to authorized user. In the case of user is linked to some role, and that role is set in Roles(parameter) the function will return true and user can access to some data, if not access is denied.

 

 

Examples

 

        public ActionResult Login(LoginViewModel login, string ReturnUrl)

        {

            if (!ModelState.IsValid)

                ModelState.AddModelError("", "Введені дані не вірні");

            else

            {

                var user = dm.GetUsers().FirstOrDefault(u => u.Email == login.EmailLogin && u.Password == login.PasswordLogin);

                if (user != null

                {

                    FormsAuthenticationService.Login(user, login.RememberMe);

                    string decodedUrl = "";

                    if (!string.IsNullOrEmpty(ReturnUrl))

                        decodedUrl = Server.UrlDecode(ReturnUrl);

                    if (Url.IsLocalUrl(decodedUrl))

                        return Redirect(decodedUrl);

                    else

                        return RedirectToAction("UserPage");

                }

                else

                    ModelState.AddModelError("", "Не вірний логін чи пароль!");

            }

            return PartialView("Index");

        }

 

 

It is ActionResult Login from my  AccountController, it takes the LoginViewModel, which has the login and password entered by user. Next step is validation – this is the model if it is not ok  action returns an error. After that I`m looking for the object of the user in DB using the login data, if object is equals to null the login or password is wrong, in other case system needs to authorize the user. After authorization system tries to redirect user to requested page but now as authorized.

 

 

Example of using the custom attribute

 

    [AuthenticateAttribute]

    public class HomeController : Controller

    {

        [AuthenticateAttribute(allowAnonymus:true)]

        public ActionResult Index()

        {

            return View();

        }

 

        [AuthenticateAttribute(roles = "admins-moderator/customer.simplejustuser")]

        public ActionResult auto()

        {

            return View();

        }

    }

 

 

  As you see the access to the HomeController only for authorized users. However every one can access Index() action, because it set allowAnonymus parameter to true. And to access the auto() action user needs to be linked to one of this roles - admin, moderator, customer, simple, justuser. The order of roles or some spaces or punctuation marks is not required. It is because of IsInRole() function (see above).

 

That’s all. If you have any question you can ask them below. Thanks.

     850       Author -

Leave Comment


Comments

 Judi          5/12/2018 2:33:01 PM

D4eCsd https://www.genericpharmacydrug.com

 mike11          4/18/2018 2:06:08 AM

sTfdsd https://www.genericpharmacydrug.com

 mike11          4/16/2018 6:52:44 PM

bRuSvy https://www.genericpharmacydrug.com

 DavidBed          3/26/2018 12:53:18 AM

http://www.microsmog.com/

 DavidBed          3/25/2018 7:32:01 PM

http://www.ip-web-law.com/

 HolaBromz          3/20/2018 5:24:36 AM

http://google0123.com/

 GoldenTabs          1/9/2018 10:38:35 AM

Wk1EJN https://goldentabs.com/

 JimmiNu          9/11/2017 1:31:52 PM

KuSL2N http://www.FyLitCl7Pf7ojQdDUOLQOuaxTXbj5iNG.com

 rov pc          8/23/2017 5:46:25 PM

thanks for the posts,it'right! get free now rov pc http://rov.appdod.com