4

I am calling a service, and I need to pass the user's permanent security token with every request I make.

In order to do that, I've added this method to my base controller class:

protected UserData getUsr()
{
        try
        {
            UserData usr = new UserData();
            usr.SecurityToken = Session["secToken"].ToString();

            MembershipUser mvcUser = Membership.GetUser(HttpContext.User.Identity.Name);
            usr.Id = (int)mvcUser.ProviderUserKey;

            return usr;
        }
        catch (Exception ex)
        {
            log.Debug("Could not create usr object", ex);
            throw new Exception("Could not authenticate");
        }
    }

This issue here is that sometimes the User.Identity data out-lasts the session data, causing weird bugs to happen with the user seeing they are logged in but then their requests failing.

Is there a better way to store this token/can I store it in such a way that it will expire whenever the User.Identity object expires?

Also, if anyone knows of some good basic understanding examples/documentation for HttpContext and MVC authorize filters that would be great.

tereško
  • 58,060
  • 25
  • 98
  • 150
John Zumbrum
  • 2,786
  • 8
  • 36
  • 60
  • You could simply check if one of the values, the token or the User.Identity data is not valid anymore. Then the user needs to login again – middelpat Nov 01 '12 at 11:00
  • Yes, but that needs to happen wherever MVC checks the authorize filter, otherwise they can get to a page, and spend 10 minutes filling out a form only to have it rejected because their token is expired. – John Zumbrum Nov 01 '12 at 13:58
  • I've looked at some other questions, and overriding the MVC onauthorize method was pretty effective. It didn't quite solve the problem though, so I'm going to be searching for the onauthenticate method (whatever that is) and see if I can override that instead. – John Zumbrum Nov 07 '12 at 22:18

4 Answers4

5

I would go for storing the security token of the user in the forms authentication cookie itself. The FormsAuthenticationTicket class contains an UserData property where you can include your additional information.

The value specified in the UserData property is included as part of the authentication ticket cookie and, like the other ticket fields, is encrypted and validated based on the forms authentication system's configuration.

Here is an article that described how you can store additional information to the forms authentication cookie.

This is a big article that explains much about storing additional data into the forms auth. cookie and how you could read it. The code is written in VB and not well formatted. You have to scroll down to the Step 4: Storing Additional User Data in the Ticket.

This thread will give you a quick answer how you could read the UserData from the cookie.

I would go for creating a custom ValueProvider like the one described here that will read the security token from the auth. cookie and feed to the action parameters.

Community
  • 1
  • 1
VJAI
  • 32,167
  • 23
  • 102
  • 164
  • I like this solution because it's easy, and it ensures that the two pieces of data are always going to be there at the same time. – John Zumbrum Nov 07 '12 at 21:16
1

You can place the users security token, IP address, and a time-stamp in a string. Encrypt the string with a symmetric algorithm such as AES and place it as a cookie. Then change your code to read from the cookie. You can validate that the ip address in the cookie matches the users ip address, this will prevent someone stealing the cookie value and replaying it. Here is the MSDN documentation on AES (Rjindael is the original name). In this scheme, the token will not expire until the cookie expires and/or your timeout is reached. I do highly recommend you put a timeout and not make it forever or persistent, it will make the scheme less secure to exclude a timeout. Also put the time-stamp at the beginning of your cookie value, because of CBC mode on these algorithms it will affect the way the encrypted string looks because of the changes in bits at the begining (Avalanche effect).

The ASP.NET membership provider also has an authentication cookie so this cookie should not expire before the membership cookie. Sessions have to expire on a timeout because there is no guarantee that the user is still there as HTTP is stateless whereas the cookie is under the control of the user and is passed every single time a request is made.

getUsr function

protected UserData getUsr()
{
    try
    {
        UserData usr = new UserData();

        string token = Request.Cookies["secToken"].Value;

        // implement RijndaelManaged encryption/decryption scheme
        // this can also be serialized as an object to make cleaner
        var tokenValues = Decrypt(token).Split(',');

        // The timeout expired
        if (DateTime.Now > DateTime.Parse(tokenValues[1]))
        {
            throw new Exception("Timeout");
        }

        // someone stole this cookie or is on a different internet connection
        if (tokenValues[0] != System.Web.HttpContext.Current.Request.UserHostAddress)
        {
            throw new Exception("Invalid IP");
        }

        // You're ok everything checks out
        usr.SecurityToken = tokenValues[3].ToString();

        MembershipUser mvcUser = Membership.GetUser(HttpContext.Current.User.Identity.Name);
        usr.Id = (int)mvcUser.ProviderUserKey;

        return usr;
    }
    catch (Exception ex)
    {
        log.Debug("Could not create usr object", ex);
        throw new Exception("Could not authenticate");
    }
}
nerdybeardo
  • 4,655
  • 23
  • 32
  • I'm worried about the security of this approach; is it industry standard to store this kind of information in a cookie? Also, and more importantly, how do I handle timeouts? ASP.net membership cookie resets the timeout to 30 minutes every time the user hits a page, which means I'd need to rewrite my auth cookie each time too. Would I need to override the default behavior of some ASP.NET method? – John Zumbrum Nov 03 '12 at 16:39
  • One issue could be that the IP address the user is coming from could be a shared IP and therefore a user on the same network could hijack the cookie. As far as the security of the data being compromised, I would say it is highly unlikely that the cookie could be decrypted based on the algorithm (AES) itself, it will depend on your key generation, where and how you store that key. Sessions can be hijacked as well because the session id is sent as a cookie, an intermediary can steal and replay it and do the same thing. http://codebutler.com/firesheep/ showed how that can be done. – nerdybeardo Nov 03 '12 at 17:55
  • As for timeouts you just need to put a datetime stamp in your cookie value as part of what is encrypted, you can reset that for 30 minutes each time the cookie is verified and re-write the cookie, that may be a little overkill though so maybe only do it if there is a short time left, e.g. set it for 30 minutes and if there's only 5 minutes left then recreate and rewrite the cookie. This way you're not writing the cookie for every single request. – nerdybeardo Nov 03 '12 at 18:06
  • Also the forms authentication ticket works in much the same way. Here is some information on how the authentication ticket works http://support.microsoft.com/kb/910443 – nerdybeardo Nov 03 '12 at 18:12
1

Maybe what I am saying is very stupid, but in the past I had a similar problem and I solved it by simply setting the session expiration time greater than than the logged in expiration time. Whenerver, you are able to enter the web siteb with the security token you refresh the session data, so for sure they will last for the whole time the user is logged in. The fact that the session has a greater duration cannot cause problems, since just a logged in user can use that data, and when a new user logs in the old session entry is replaced.

Francesco Abbruzzese
  • 4,139
  • 1
  • 17
  • 18
  • What if they close their browser? This will remove their session; will it also remove their auth cookies? – John Zumbrum Nov 04 '12 at 15:25
  • both session and auth are handled by cookies it is enought to apply the same settings to them with the only exception the session expiration time is longer than the login time. If both cookies are set as not persistent (session cookies)...yes. However session will continue wasting resources on the server till the expiration of the session is reached, then they data structures are cleared. – Francesco Abbruzzese Nov 04 '12 at 18:53
0

If User.Identity outlasts the Session, why not store the token as a Claim in the Identity? Something like:

var claims = new[]
{
    new Claim("access_token", string.Format("Bearer {0}", token)),
};

var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);

Request.GetOwinContext().Authentication.SignIn(options, identity);
Philip
  • 3,135
  • 2
  • 29
  • 43