Ošetření chyby obnovy přihlášení pomoci SessionAuthenticationModule

Tomáš Holan       19. 8. 2013       ASP.NET/IIS, Bezpečnost, WIF       8921 zobrazení

Pokud v ASP.NET aplikaci používáme technologii WIF, zpravidla využíváme HTTP modul SessionAuthenticationModule. Ten se stará o to, že po přihlášení je vytvořeno cookie, které obsahuje serializované claims přihlášeného uživatele a při každém requestu provádí rekonstrukci objektu ClaimsPrincipal z dat obsažených v tomto cookie. Navíc pokud naše aplikace podporuje možnost zapamatování přihlášení, je toto cookie vytvořeno jako persistentní, takže při vstupu uživatele do naší aplikace je i při prvním requestu již cookie přítomno a objekt principál obnoven.

Více jsem o autentizaci s využitím technologie WIF, včetně příkladu jednoduché aplikace, psal zde.

Při využívání modulu SessionAuthenticationModule můžeme ale narazit na to, že pokud při obnově claims z cookie dojde k nějaké chybě, je tato chyba standardně odchycena jako neošetřená výjimka. A pokud se právě jedná o obnovování zapamatovaného přihlášení, důsledek je to, že nám aplikace vůbec nenaběhne.

V praxi se s tímto problémem můžeme setkat po změně v konfiguraci běhového prostředí naší aplikace, tedy pokud například změníme identitu, pod kterou běží aplikační pool naší aplikace v IIS nebo pokud dojde ke změně machine key web serveru apod.

Například po změně identity tj. v případě kdy se dekriptování dat cookie provádí pod jinou identitou, než pod tou, která cookie vytvořila, dojde konkrétně k této chybě:

[CryptographicException: Key not valid for use in specified state.]
at System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope)
at Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded)

[InvalidOperationException: ID1073: A CryptographicException occurred when attempting to decrypt the cookie using the ProtectedData API (see inner exception for details). If you are using IIS 7.5, this could be due to the loadUserProfile setting on the Application Pool being set to false. ]
at Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded)
at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound)
at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver)
at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver)
at Microsoft.IdentityModel.Web.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie)
at Microsoft.IdentityModel.Web.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken)
at Microsoft.IdentityModel.Web.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs)
at Microsoft.Crm.Authentication.Claims.CrmSessionAuthenticationManager.OnAuthenticateRequest(Object sender, EventArgs args)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Pokud problém nastane v debug prostředí, je to sice otravné, ale chybu můžeme případně obejít tím, že si z cache prohlížeče odstraníme příslušné cookie. Pokud ale provedeme nějakou změnu na produkčním hostingu, nebudou z toho mít naši existující uživatele, kteří si nechali zapamatovat přihlášení, vůbec radost (a u nich by jsme znalost s provedením odstraněním cookie obecně předpokládat neměli).

Jak tedy problém řešit?

Řešením je chybu ošetřit tak, že se v takovém případě obnovení přihlášení sice neprovede – uživatelé se budou muset znovu přihlásit (a znovu zvolit zapamatování přihlášení), ale aplikace jim normálně naběhne.

K tomu využijeme událost SessionSecurityTokenReceived, kterou SessionAuthenticationModule nabízí. Její registraci provedeme v souboru global.asax v handleru Application_Start a instanci SessionAuthenticationModulu získáme vlastností SessionAuthenticationModule třídy FederatedAuthentication.

Ve vlastní obsluze události nejprve nastavíme e.Cancel na true, aby se po skončení obsluhy již neprováděla žádná výchozí akce. Pak si provedeme obnovení objektu principál sami (voláním metody AuthenticateSessionSecurityToken) a pro toto volání ošetříme výjimky FederatedAuthenticationSessionEndingException (to modul provádí i standardně) a hlavně SecurityTokenException.

Celý kód ve verzi pro .NET 4.5 vypadá takto:

protected void Application_Start(object sender, EventArgs e)
{
    FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenReceived += SessionAuthenticationModule_SessionSecurityTokenReceived;
}
    
protected void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
{
    e.Cancel = true;

    var sessionAuthenticationModule = (SessionAuthenticationModule)sender;
    try
    {
        sessionAuthenticationModule.AuthenticateSessionSecurityToken(e.SessionToken, false);
    }
    catch (FederatedAuthenticationSessionEndingException)
    {
        sessionAuthenticationModule.SignOut();
    }
    catch (System.IdentityModel.Tokens.SecurityTokenException)
    {
        sessionAuthenticationModule.SignOut();
    }
}

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback