neildt
neildt

Reputation: 5362

Custom MVC Authentication without SetAuthCookie()

Because of the requirements of my project, I'm wanting to provide custom authenticate for my MVC controller actions. Therefore, I will not be using SetAuthCookie().

Intially I set a cookie as follows;

string userData = EncDec.MakeString(user.Email + "|" + user.UserId);

//the Cookie and FormsAuthenticationTicket expiration date/time is the same
DateTime cookieExpiry = DateTime.Now.AddMinutes(AccountPage.MvcApplication.COOKIE_EXPIRY_MINUTES);

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
          1,                                     // ticket version
          user.UserName,                         // authenticated username
          DateTime.Now,                          // issueDate
          cookieExpiry,                          // expiryDate
          false,                                 // true to persist across browser sessions
          userData,                              // can be used to store additional user data
          FormsAuthentication.FormsCookiePath);  // the path for the cookie

string encryptedTicket = FormsAuthentication.Encrypt(ticket);

//create the cookie
HttpCookie cookie = new HttpCookie("ADV_" + Extensions.ControllerExtensionMethods.GetGuid(this), encryptedTicket);
cookie.Secure = true;
cookie.HttpOnly = true;
cookie.Expires = cookieExpiry;
Response.Cookies.Add(cookie);

The HttpCookie is being saved in the client browser with a encrypted FormsAuthenticationTicket.

Then within my controller actions, whenever I need to check and verify that the user is authenticated I call this method;

public static FormsAuthenticationTicket IsAuthenticated(string guid)
{
     HttpCookie cookie = HttpContext.Current.Request.Cookies["ADV_" + guid];

     if (cookie != null)
     {
           string encryptedTicket = cookie.Value;
           FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(encryptedTicket);

            if (!ticket.Expired)
            {
               //if the user is authenticated and the cookie hasn't expired we increase the expiry of the cookie - keep alive
               DateTime cookieExpiry = DateTime.Now.AddMinutes(AccountPage.MvcApplication.COOKIE_EXPIRY_MINUTES);

               //create a new ticket based on the existing one
               FormsAuthenticationTicket newTicket = new FormsAuthenticationTicket(
                      ticket.Version,                        // ticket version
                      ticket.Name,                           // authenticated username
                      ticket.IssueDate,                      // issueDate
                      cookieExpiry,                          // expiryDate, changed to keep alive if user is navigating around site
                      false,                                 // true to persist across browser sessions
                      ticket.UserData,                       // can be used to store additional user data
                      ticket.CookiePath);                    // the path for the cookie

               string newEncryptedTicket = FormsAuthentication.Encrypt(newTicket);

               //keep alive
               HttpCookie newCookie = new HttpCookie("ADV_" + guid, newEncryptedTicket);
               newCookie.Secure = true;
               newCookie.HttpOnly = true;
               newCookie.Expires = cookieExpiry;

               HttpContext.Current.Response.Cookies.Set(newCookie);

               return newTicket;
          }
     }

            return null; 
}

Every time the user is re-authenticated, I am increasing the time out of when the cookie will expire, so that the login is keep alive.

Everything seems to work fine, and the users are correctly authenticated, and if they aren't authenticated I redirect them to a login page, and they can't access methods if they aren't authenticated either.

My questions are:

  1. Is this way of dealing with the authentication secure.
  2. Is there anything I should be aware of, in terms of a security risk.

Thanks.

Upvotes: 0

Views: 1674

Answers (1)

Derek
Derek

Reputation: 8640

You basically need to look at creating a Custom Authentication Attribute.

I'm not going to provide the actual implementation here, but this will put you on the right path.

Here's the basic representation :-

 public class GoogleAuthAttribute : FilterAttribute, IAuthenticationFilter
    {
        public void OnAuthentication(AuthenticationContext filterContext)
        {

            IIdentity ident = filterContext.Principal.Identity;

            if (!ident.IsAuthenticated || !ident.Name.EndsWith("@google.com"))
            {
                filterContext.Result = new HttpUnauthorizedResult();
            }
        }

        public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
        {
            if (filterContext.Result == null || filterContext.Result is HttpUnauthorizedResult)
            {
                filterContext.Result =
                    new RedirectToRouteResult(new RouteValueDictionary
                    {
                        {"controller", "GoogleAccount"},
                        {"action", "Login"},
                        {"returnUrl", filterContext.HttpContext.Request.RawUrl}
                    });
            }

        }
    }

I've took this from the Apress Book i'm currently reading on MVC5. If OnAuthentification fails, you set the Result property of the AuthenticationContext, this is then passed to the AuthenticationChallengeContext, where you can add your challenge code.

In my example, the user is redirected to the login page.

All you need t do, is place this AuthentificationAttribute on the Action Methods you require.

You should be able to build in or work your custome security code in to this.

You should really ask yourself if its a good idea to be adding custom security measures, as it can lead to more problems that you want.

Upvotes: 1

Related Questions