views:

181

answers:

3

I am having a hard time implementing "Remember Me" functionality in an MVC application with a custom principal. I have boiled it down to ASP.NET not retrieving the authentication cookie for me. I have included a snaphot below from Google Chrome.

  1. Shows the results of Request.Cookies that is set within the controller action and placed in ViewData for the view to read. Notice that it is missing the .ASPXAUTH cookie

  2. Shows the results from the Chrome developer tools. You can see that .ASPXAUTH is included here.

alt text

Does anyone know what the issue may be here? Why does ASP.NET not read this value from the cookie collection?

My application uses a custom IPrincipal. BusinessPrincipalBase is a CSLA object that ust implements IPrincipal. Here is the code for that:

[Serializable()]
public class MoralePrincipal : BusinessPrincipalBase
{
    private User _user;

    public User User
    {
        get
        {
            return _user;
        }
    }

    private MoralePrincipal(IIdentity identity) : base(identity)
    {
        if (identity is User)
        {
            _user = (User)identity;
        }
    }

    public override bool Equals(object obj)
    {
        MoralePrincipal principal = obj as MoralePrincipal;
        if (principal != null)
        {
            if (principal.Identity is User && this.Identity is User)
            {
                return ((User)principal.Identity).Equals(((User)this.Identity));
            }
        }
        return base.Equals(obj);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }

    public static bool Login(string username, string password)
    {
        User identity = User.Fetch(username, password);
        if (identity == null || !identity.IsAuthenticated)
        {
            identity = (User)User.UnauthenicatedIdentity;
        }

        MoralePrincipal principal = new MoralePrincipal(identity);
        Csla.ApplicationContext.User = principal;
        Context.Current.User = identity;

        return identity != null && identity.IsAuthenticated;
    }

    public static void Logout()
    {
        IIdentity identity = User.UnauthenicatedIdentity;
        MoralePrincipal principal = new MoralePrincipal(identity);
        ApplicationContext.User = principal;
        Context.Current.User = identity as User;
    }

    public override bool IsInRole(string role)
    {
        if (Context.Current.User == null || Context.Current.Project == null)
        {
            return false;
        }

        string userRole = Context.Current.User.GetRole(Context.Current.Project.Id);
        return string.Compare(role, userRole, true) == 0;
    }

The application also uses a custom membership provider. Here is the code for that.

public class MoraleMembershipProvider : MembershipProvider
{
    public override bool ValidateUser(string username, string password)
    {
        bool result = MoralePrincipal.Login(username, password);
        HttpContext.Current.Session["CslaPrincipal"] = ApplicationContext.User;
        return result;
    }

    #region Non-Implemented Properties/Methods

    public override string ApplicationName
    {
        get
        {
            return "Morale";
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    // Everything else just throws a NotImplementedException

    #endregion
}

I do not think that any of this is related because the bottom line is that the Request.Cookies does not return the authentication cookie. Is it related to the size of the cookie? I heard there are issues to the size of the cookie.

UPDATE: It seems that the issue revolves around subdomains. This site was being hosted with a subdomain and the cookie domain was left blank. Does anyone have any pointers on how I can get the auth cookie to work with all domains (e.g. http://mydomain.com, http://www.mydomain.com, and http://sub.mydomain.com)?

+1  A: 

also did you check this?

http://stackoverflow.com/questions/1900584/aspxauth-cookie-is-not-being-saved

I'm not sure if that would be the cause of the cookie showing up in chrome but not actually being passed to the browser or if it would prevent the cookie from saving but also worth a look.

chrisjlong
I worked on reducing the size and I still cannot get the cookie from the Request.Cookies collection unless within the same the session. I know that this is not a session cookie and it is persisted to disk.
Jamie Wright
+1  A: 

If you are trying to store the actual User object in the cookie itself, it is probably too big to store as a cookie. I am not too familiar with the MVC authentication stuff, but in web forms I generally do the following:

FormsAuthentication.RedirectFromLoginPage(user_unique_id_here, false);

The second parameter is for the persistency you are looking for.

From there I create a custom context (UserContext) that I populate via HttpModule that gives me access to all the user and role information.

Since I do not develop in MVC (yet) or CSLA, I'm not sure how much more help I can be. If I were you, I would also ditch the custom membership provider. You might as well just call MoralePrincipal.Login directly in your Authentication controller.

sestocker
Yes, that was my thought after I was typing this out. I think the serialized version of my User object is too large. I may have to create a different object for IIdentity that is smaller and can be safely serialized to disk.
Jamie Wright
http://stackoverflow.com/questions/2224562/asp-net-formsauthentication-redirect-loses-the-cookie-between-redirect-and-applic
Jamie Wright
I worked on using a smaller object that is serialized and I still get the same issue. I am stuck once again.
Jamie Wright
+1  A: 

The rememberMe stuff should be set by the FormsAuthenticationService (in MVC2) or the FormsAuthentication static class in MVC1, if you're using the 'regular' AccountController's code. If you changed that code, did you remember to add in the (optional) boolean param indicating whether to use a persistent cookie or not?

It sounds to me like you're getting a session cookie, but not a persistent cookie.

Paul
The cookie is present in the browser's cookies. I have verified this using Firebug in Firefox and Developers Tools in Chrome. The issue is that .NET is just not returning the cookie in the collection. It is not a session cookie.
Jamie Wright