ASP.NET_SessionId + OWIN Cookies do not send to browser Ask Question

ASP.NET_SessionId + OWIN Cookies do not send to browser Ask Question

I have a strange problem with using Owin cookie authentication.

When I start my IIS server authentication works perfectly fine on IE/Firefox and Chrome.

I started doing some testing with Authentication and logging in on different platforms and I have come up with a strange error. Sporadically the Owin framework / IIS just doesn't send any cookies to the browsers. I will type in a username and password which is correct the code runs but no cookie gets delivered to the browser at all. If I restart the server it starts working then at some point I will try login and again cookies stop getting delivered. Stepping over the code does nothing and throws no errors.

 app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            CookieHttpOnly = true,
            AuthenticationType = "ABC",
            LoginPath = new PathString("/Account/Login"),
            CookiePath = "/",
            CookieName = "ABC",
            Provider = new CookieAuthenticationProvider
               {
                  OnApplyRedirect = ctx =>
                  {
                     if (!IsAjaxRequest(ctx.Request))
                     {
                        ctx.Response.Redirect(ctx.RedirectUri);
                     }
                 }
               }
        });

And within my login procedure I have the following code:

IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
                            authenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

var authentication = HttpContext.Current.GetOwinContext().Authentication;
var identity = new ClaimsIdentity("ABC");
identity.AddClaim(new Claim(ClaimTypes.Name, user.Username));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.User_ID.ToString()));
identity.AddClaim(new Claim(ClaimTypes.Role, role.myRole.ToString()));
    authentication.AuthenticationResponseGrant =
        new AuthenticationResponseGrant(identity, new AuthenticationProperties()
                                                   {
                                                       IsPersistent = isPersistent
                                                   });

authenticationManager.SignIn(new AuthenticationProperties() {IsPersistent = isPersistent}, identity);

Update 1: It seems that one cause of the problem is when I add items to session the problems start. Adding something simple like Session.Content["ABC"]= 123 seems to create the problem.

What I can make out is as follows: 1) (Chrome)When I login I get ASP.NET_SessionId + my authentication cookie. 2) I go to a page that sets a session.contents... 3) Open a new browser (Firefox) and try login and it does not receive an ASP.NET_SessionId nor does it get a Authentication Cookie 4) Whilst the first browser has the ASP.NET_SessionId it continues to work. The minute I remove this cookie it has the same problem as all the other browsers I am working on ip address (10.x.x.x) and localhost.

Update 2: Force creation of ASPNET_SessionId first on my login_load page before authentication with OWIN.

1) before I authenticate with OWIN I make a random Session.Content value on my login page to start the ASP.NET_SessionId 2) then I authenticate and make further sessions 3) Other browsers seem to now work

This is bizarre. I can only conclude that this has something to do with ASP and OWIN thinking they are in different domains or something like that.

Update 3 - Strange behaviour between the two.

Additional strange behaviour identified - Timeout of Owin and ASP session is different. What I am seeing is that my Owin sessions are staying alive longer than my ASP sessions through some mechanism. So when logging in: 1.) I have a cookied based auth session 2.) I set a few session variables

My session variables(2) "die" before the owin cookie session variable forces re-login, which causes unexpected behaviour throughout my entire application. (Person is logged in but is not really logged in)

Update 3B

After some digging I saw some comments on a page that say the "forms" authentication timeout and session timeout need to match. I am thinking normally the two are in sync but for whatever reason the two are not in sync.

Summary of Workarounds

1) Always create a Session first before authentication. Basically create session when you start the application Session["Workaround"] = 0;

2) [Experimental] if you persist cookies make sure your OWIN timeout / length is longer than your sessionTimeout in your web.config (in testing)

ベストアンサー1

I have encountered the same problem and traced the cause to OWIN ASP.NET hosting implementation. I would say it's a bug.

Some background

My findings are based on these assembly versions:

  • Microsoft.Owin, Version=2.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
  • Microsoft.Owin.Host.SystemWeb, Version=2.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
  • System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

OWIN uses it's own abstraction to work with response Cookies (Microsoft.Owin.ResponseCookieCollection). This implementation directly wraps response headers collection and accordingly updates Set-Cookie header. OWIN ASP.NET host (Microsoft.Owin.Host.SystemWeb) just wraps システム.Web.HttpResponseそして、それはヘッダーコレクションです。したがって、OWINを通じて新しいクッキーが作成されると、応答Cookie の設定ヘッダーが直接変更されます。

しかし、ASP.NETはレスポンスCookieを扱うために独自の抽象化も使用しています。これは次のように公開されています。システム.Web.HttpResponse.Cookiesプロパティとシールクラスによって実装されるシステム.Web.HttpCookieコレクションこの実装ではレスポンスをラップしませんCookie の設定ヘッダーを直接使用しますが、いくつかの最適化と少数の内部通知を使用して、変更された状態を応答オブジェクトに明示します。

そして、リクエストの存続期間の後半で、HTTPCookieコレクション変更された状態がテストされます(System.Web.HttpResponse.GenerateResponseHeadersForCookies())とクッキーはシリアル化され、Cookie の設定ヘッダー。このコレクションが特定の状態にある場合、まず Set-Cookie ヘッダー全体がクリアされ、コレクションに保存されている Cookie から再作成されます。

ASP.NETセッション実装では、システム.Web.HttpResponse.CookiesASP.NET_SessionId Cookie を保存するためのプロパティ。また、ASP.NET セッション状態モジュールにはいくつかの基本的な最適化があります (System.Web.SessionState.SessionStateModule) は、s_sessionEverSet という静的プロパティを通じて実装されます。これは、説明の必要がないほどです。アプリケーションでセッション状態に何かを保存する場合、このモジュールはリクエストごとにもう少し作業を行います。


ログインの問題に戻る

これらすべての要素があれば、シナリオを説明することができます。

ケース1 - セッションが設定されていない

System.Web.SessionState.SessionStateModule、s_sessionEverSetプロパティはfalseです。セッション状態モジュールによってセッションIDは生成されず、システム.Web.HttpResponse.Cookiesコレクションの状態は変更が検出されませんでしたこの場合、OWIN クッキーはブラウザに正しく送信され、ログインが機能します。

ケース 2 - セッションはアプリケーションのどこかで使用されたが、ユーザーが認証を試みる前に使用されていない

System.Web.SessionState.SessionStateModule、s_sessionEverSetプロパティがtrueの場合、セッションIDは次のように生成されます。セッション状態モジュール、ASP.NET_SessionIdが追加されますシステム.Web.HttpResponse.Cookiesコレクションは、ユーザーのセッションが実際には空であるため、リクエストの有効期間の後半で削除されます。この場合システム.Web.HttpResponse.Cookiesコレクションの状態は変更されたと検出そしてCookie の設定クッキーがヘッダー値にシリアル化される前に、まずヘッダーがクリアされます。

この場合、OWIN 応答 Cookie は「失われ」、ユーザーは認証されず、ログイン ページにリダイレクトされます。

ケース3 - ユーザーが認証を試みる前にセッションが使用される

System.Web.SessionState.SessionStateModule、s_sessionEverSetプロパティがtrueの場合、セッションIDは次のように生成されます。セッション状態モジュール、ASP.NET_SessionIdが追加されますシステム.Web.HttpResponse.Cookies内部最適化によりシステム.Web.HttpCookieコレクションそしてSystem.Web.HttpResponse.GenerateResponseHeadersForCookies() Set-Cookie ヘッダーは最初にクリアされませんただし更新のみです。

この場合、OWIN 認証 Cookie と ASP.NET_SessionId Cookie の両方が応答として送信され、ログインが機能します。


クッキーに関するより一般的な問題

ご覧のとおり、問題はより一般的であり、ASP.NETセッションに限定されません。OWINをホストしている場合は、Microsoft.Owin.Host.SystemWebそしてあなた/何かが直接使用していますシステム.Web.HttpResponse.Cookiesコレクションにはリスクが伴います。

例えばこれはうまくいく両方の Cookie がブラウザに正しく送信されます...

public ActionResult Index()
{
    HttpContext.GetOwinContext()
        .Response.Cookies.Append("OwinCookie", "SomeValue");
    HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue";

    return View();
}

しかしこれはそしてOwinCookieは「失われました」...

public ActionResult Index()
{
    HttpContext.GetOwinContext()
        .Response.Cookies.Append("OwinCookie", "SomeValue");
    HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue";
    HttpContext.Response.Cookies.Remove("ASPCookie");

    return View();
}

どちらも VS2013、IISExpress、デフォルトの MVC プロジェクト テンプレートからテストされました。

おすすめ記事