Strašlivé dědictví přípon aneb preCondition "managedHandler" a HTTP moduly

Na počátku byla tma. Pak se zrodil HyperText Transfer Protocol. Mezitím pravda nastala celá řada dalších věcí, ale ty nejsou pro náš příběh příliš podstatné. Podstatné je, co se dělo potom. Webové servery byly úplně původně navrženy spíš jako úložiště dat, než jako aplikační platforma. Na server se uložil soubor, klient si jej vyžádal a server mu ho poslal, aniž se sebeméně zajímal o jeho obsah. Bylo to takové jeddnodušší FTPko.

Základ webových aplikací, tak jak je známe dnes, byl položen teprve ve chvíli, kdy se web server začal zajímat o to, co vlastně posílá. Kdy ho bylo možno zkonfigurovat tak, aby za určitých okolností klientovi neposlal obsah požadovaného souboru, alébrž spustil jakýsi kód a klientovi poslal výsledek. Historicky za tímto účelem existovaly dvě technologie: CGI (Common Gateway Interface) a ISAPI (Internet Server Application Programming Interface). Ač je jejich princip fungování dost odlišný, jedno mají společné: požadavky na ně se typicky mapují pomocí přípon. Podle přípony požadovaného souboru server rozpoznal, co s ním má provést. Soubory s příponou .php se tak poslaly jednomu procesoru, .asp jinému a cokoliv neznámého poslalo beze změny.

Na platformě Microsoft byl tento přístup ortodoxně dodržován Internet Information Services až do verze 6.0. Ve výchozí konfiguraci byly jednotlivé typy aplikačních platforem rozděleny právě pomocí přípon. V zásadě vám nic nebránilo v tom, aby v rámci jednoho virtuálního web serveru vedle sebe běželo například ASP.NET, ASP a PHP. Jednotlivé platformy o požadavcích, které nešly na "jejich" přípony prostě nevěděly.

Pak přišla verze 7.0 se zcela novou architekturou, kterou sice je možné pokládat za ideového nástupce ISAPI extensions, ale ve které na příponách až tak nezáleželo – protože tou dobou se z různých důvodů z přípony stala persona non grata. HTTP moduly, známé už od ASP.NET verze 1.0, najednou dostaly nové pole působnosti: používají se na všechny požadavky, bez ohledu na přípony.

Nové možnosti ale přinesly i nové problémy. Ukážeme si to na příkladu modulů pro Forms Authentication a URL Authorization. Na IIS 6.0 se toto zabezpečení vztahovalo pouze na ASP.NET stránky. I když jste pomocí URL authorization zakázali uživateli přístup, stále mohl číst například obrázky nebo CSS soubory. Pokud byste takovou aplikaci beze změny přenesli na IIS 7, její chování by se změnilo. Autorizační pravidla by se začala vztahovat na všechny soubory a dokud byste nepřihlášeným uživatelům explicitně nepovolili přístup např. ke kaskádovým stylům a obrázkům, zobrazila by se např. přihlašovací stránka bez nich, jinak než bylo původně zamýšleno.

Pročež přišel Microsoft s preCondition zvanou managedHandler. Obecně mechanismus preConditions slouží k natažení správné verze modulu či handleru v závislosti na verzi .NET runtime nebo architektuře procesoru (32/64- bit) a vyhodnocuje se jenom jednou, při spouštění application poolu. Leč managedHandler je výjimkou: vyhodnocuje se při každém požadavku a pokud je přítomen, spustí se pouze v případě, že je požadavek dalším nastavením mapován na handler psaný v managed kódu (což se stále děje typicky pomocí přípon). V zásadě lze tedy pomocí této preCondition emulovat chování předchozích verzí.

Výchozí nastavení je takové, že všechny managed moduly, které jsou součástí .NET Frameworku, mají tuto podmínku nastaveny. Když se podíváte do svého souboru applicationHost.config, najdete tam něco na tento způsob:

<system.webServer>

    <modules>

        <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" preCondition="managedHandler" />

        <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition="managedHandler" />

        <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" preCondition="managedHandler" />

        <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="managedHandler" />

        <add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" preCondition="managedHandler" />

        <add name="RoleManager" type="System.Web.Security.RoleManagerModule" preCondition="managedHandler" />

        <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" preCondition="managedHandler" />

        <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" preCondition="managedHandler" />

        <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" preCondition="managedHandler" />

        <add name="Profile" type="System.Web.Profile.ProfileModule" preCondition="managedHandler" />

        <add name="UrlMappingsModule" type="System.Web.UrlMappingsModule" preCondition="managedHandler" />

    </modules>

</system.webServer>

(seznam modulů odpovídá verzi runtime 2.0, ve verzi 4.0 jich ještě několik přibylo)

Pokud si napíšete a zaregistrujete vlastní HTTP modul, záleží na vás, zda preCondition="managedHandler" použijete či nikoliv.

Pokud chcete, aby se konkrétní modul (typicky právě FormsAuthentication a UrlAuthorization) použil, musíte ho ve web.configu své aplikace odregistrovat a zaregistrovat znovu, tentokrát bez preCondition:

<system.webServer>

    <modules>

        <remove name="FormsAuthentication" />

        <remove name="UrlAuthorization" />

        <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />

        <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />

    </modules>

</system.webServer>

Pokud chcete použít všechny takové moduly, má pro vás IIS k dispozici techniku dle mého názoru dosti zvrhlou, override na override. Konfigurační sekce modules totiž oplývá atributem s poetickým názvem runAllManagedModulesForAllRequests. Pokud je nastaven na true, pak se preCondition="managedHandler" bude ignorovat. Toto nastavení se vám bude hodit zejména v případě, že používáte URL routing v ASP.NET 4.0, neboť i ten je standardně nastaven tak, že se aplikuje jenom v případě managed handleru. U jeho registrace v applicationHost.config vidíte v akci ještě jednu preCondition, a to požadavek na verzi .NET Runtime 4.0:

<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />

Problematice preConditions jako takových se budu věnovat v samostatném článku.

Titulek:
Text komentáře:
Vaše jméno:
Váš e-mail: (nebude zveřejněn)

WWW stránka:
Opište text z obrázku:
odpovědětodpovědět Gravatar

native <> managed module

Dobrý den, není mi jasné spouštění modulů registrovaných v applicationHost.config. Mohu mít modul psaný v MANAGED kódu, který bude registrovaný v applicationHost.config v sekci system.webServer/modules a který se bude spouštět pro každý požadavek i pokud bude mít aplikace v AppPoolu nastaveno, že nevyužívá managed code (např. jen statické HTML stránky)? Myslel jsem, že pokud modul dám do applicationHost.config a NEnastavím preCondition="managedHandler", takže to bude fungovat, ale modul se mi nespouští. Myslel jsem, že takto můžu napsat libovolné rozšíření pro IIS 7 v managed kódu (drbat se s c++ pro unmanaged modul se mi nechce) nezávisle na tom, zda aplikace je v managed kódu nebo ne. Prostě managed modul na úrovni IIS7 a ne na úrovni aplikace.

odpovědětodpovědět Gravatar

RE: native <> managed module

Prostředí pro běh je jenom jedno. Neexistuje fakticky žádná hranice mezi "na úrovni IIS 7" a "na úrovni aplikace". Jestli (např.) HTTP modul zaregistrujete na úrovni applicationHost.config nebo web.config, to nehraje žádnou roli.

Pokud tedy napíšete managed modul, bude vám fungovat jenom v application poolech, kde máte povolený běh managed kódu. To nic nevypovídá o tom, co dovolíte aplikaci, samozřejmě, té můžete dovolit jenom statické HTML, když na to přijde.

odpovědětodpovědět Gravatar

RE: native <> managed module

Díky za info, to mě celkem nemile překvapilo. Nechtěl jsem např. u PHP aplikací, které "musím trpět" povolovat v AppPoolu vůbec použití managed kódu (razím zásadu že čím méně, tím lépe). Takže jediná možnost, jak být nezávislý na vlastním nastavení aplikace (verze .NET, režim pipeline apod.) je napsat to jako nativní modul :-(.

Ještě poznámka v tomuto formuláři - ve Firefoxu klikám na odpovědět a nic se neděje... Až jsem to zkusil v IE, tak jsem pochopil, že to má dát focus na tento formulář (protože mi focus posunul). Možná by bylo dobré tento zelený blok při kliknutí na odpovědět nějak zvýraznit, aby to víc trklo trubky jako já :-).

  • Altairis
  • Nemesis
  • Microsoft MVP
  • IIS
  • ASP.NET