Archive for 'IIS7'

IIS - MySQL Membership Provider telepítése

A cél egy integrált vitruális felhasználókat kezelő rendszer létrehozása volt IIS alá, ami független az IIS Manager Userektől és természetesen a Windows felhasználói fikókoktol is, ugyanakkor elérhető az IIS FTP, WebDAV és egyéb szolgáltatásaiból. A megoldás egyik alappillére a .Net Membership rendszere.

Az én megvalósításomban az adatbázis nem a megszokott Microsoft SQL, hanem MySQL. A telepítés kicsit macerás volt egy idegesítő hiba és a konfiguráció nüanszai miatt, ráadásul mivel nem vagyok .Net fejlesztő és VS-ből soha nem próbáltam ilyen kapcsolatot létrehozni, IIS-ből sem volt könnyebb.

Kapásból vakvágányra futottam, mert Google-ban keresgéltem, megszegve ezzel az MS fejlesztők és rendszergazdák elsőszámú szabályát: használd a Support weboldalakat, mert sz@runk a google-ra és nem hagyjuk, hogy a jó megoldásokat első oldalon hozza. Szal’ elkezdtem behackelni ezt a göncöt: http://www.codeproject.com/KB/database/mysqlmembershipprovider.aspx Már az SQL táblák létrehozása egy katasztrófa, hagyjuk is.

A jó megoldást a MySQL saját connectora jelenti: Connector/Net 6.2: Nem kell félni az MSI installertől, kiválóan működik.

A Connector mellé installálni kell a MySQL ODBC Drivert is. Töltsük le a MySQL oldaláról, majd telepítsük.

IIS Managerben elég bonyolult a sok kattintgatás, ezért inkább postolok egy helyes, jól működő web.config kódot:

<!-- Előbb eltávolítjuk az alapértelmezetteket, mert az IIS hiányolja őket és a sajátunk nem fog működni-->
<connectionStrings>
        <remove name="LocalSqlServer" />
        <remove name="LocalMySqlServer" />
        <add name="LocalMySqlServer" connectionString="Datasource=localhost;Database=dbname;uid=username;pwd=password;" providerName="MySql.Data.MySqlClient" />
</connectionStrings>

<system.web>
    <roleManager enabled="true" defaultProvider="MySQLRoleProvider">
      <providers>
        <clear />
        <add name="MySQLRoleProvider" type="MySql.Web.Security.MySQLRoleProvider, MySql.Web, Version=6.0.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" connectionStringName="LocalMySqlServer" applicationName="LoginControl" />
      </providers>
    </roleManager>

<!-- autogenerateschema="true", ha nem kézzel akarjuk létrehozni a táblákat..-->
 <membership defaultProvider="MySQLMembershipAppProvider">
       <providers>
        <clear />
        <add name="MySQLMembershipAppProvider" type="MySql.Web.Security.MySQLMembershipProvider, MySql.Web, Version=6.0.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" autogenerateschema="true" connectionStringName="LocalMySqlServer" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="LoginControl" requiresUniqueEmail="true" passwordFormat="hashed" maxInvalidPasswordAttempts="7" minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="1" passwordAttemptWindow="10" passwordStrengthRegularExpression="" />
      </providers>
    </membership>

    <compilation>
      <assemblies>
        <add assembly="MySql.Data, Version=6.0.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
      </assemblies>
    </compilation>

</system.web>

Jellegzetes hibalehetőségek, amikkel én is szívtam:

1. ODBC Dirver tényleg legyen rendben, akár teszteljük is, mielőtt bármit konfigurálnánk.

2. Ha az ODBC rendben, ne felejtsük a schema=”true”-t hozzáadni a MemberShip Providerhez, mert különben nem jönnek létre a szükséges táblák a MySQL adatbázisunkban.

3. Figyeljünk, hogy ne legyen hiba a connection stringben, nem szereti a jelszóban a különleges karaktereket.

Ha mindent jól csináltunk, az IIS Manager ASP.NET / .Net Users-be belépve egyrészt nem kapunk hibát, másrészt létrejönnek adatbázisunkban a szükséges táblák és akár meg is kezdhetjük a felhasználók feltöltését. Az IIS tökéletes felhasználókezelést nyújt, nemsokára posztolom az én Flexben készült “Fancy Remote” applikációmat, ami még fejlesztés alatt áll.

IIS7 Custom Basic Authentication

Már régóta kerülgetem a Codeplex-en ezt a projektet, soha nem jutottam el addig, hogy kipróbáljam. Az a baj az IIS Basic Authentication-nel, hogy nem tudunk vele virtuális felhasználókat kezelni, csak igen komplikált módon. Akkor is csak úgy, hogy az IIS configjában tárolódnak a felhasználók adatai. A célom az volt, hogy egy külső MySQL adatbázisba valamilyen okos formában tárolódjanak az IIS virtuális felhasználói és azokat az összes IIS-es szolgáltatásból (Védett könyvtárak, FTP, WebDav, stb..) elérjem, autentikálhatóak legyenek. Pontosan erre jó a Custom Basic Authentication nevű kis projekt. Pontosabban arra, hogy egy .Net Membership Providert elérhetővé tegyen Basic Authentication formában.

Telepítése nem túl bonyolult:
Töltsük le a http://www.codeplex.com/CustomBasicAuth weboldalról (az installert, ne a forrást).
Persze gondok lesznek, különben nem ínék róla :)
Az installer.cmd a gautil.exe-t használja, ami nagy marhaság a kedves fejlesztő részéről, hiszen a .Net Framework 2 óta ez a utility nincs benn a Frameworkben, csak az SDK-ban. Kiszolgálókra meg ugyebár mióta divat SDK-t pakolni :S Az MS hivatalos álláspontja egyébként az, hogy a GACUTIL egy fejlesztői eszköz, ezért is vette ki a Frameworkből.

Itt kicsit tétováztam, mert nem igazán tudtam, mire jó egyáltalán ez a kis programocska. Aztán kiderült, hogy igazából nincs rá szükség. Fogjuk a 3db dll fájlt és másoljuk a C:/Windows/assembly könyvtárba, így bekerülnek a GAC-ba. Majd az installer kikommentelt utolsó két parancsát futtassuk le parancssorból a fájlok mappájában:

iisschema.exe /install CustomBasicAuthentication_schema.xml
IisRegMgmt CustomBasicAuth LeastPrivilege.CustomBasicAuthentication.Management.CustomBasicAuthenticationModuleProvider LeastPrivilege.CustomBasicAuthentication.Management.dll

Voila, készen is vagyunk, az IISManager-ben a Site-unk Authentication panelján már ott kell lennie a Custom Basic Authentication opciónak is. Az Edit-re kattintva konfigurálhatjuk, hogy melyik providert használja. Tiltsuk le az összes többi Authentication módot és próbáljuk ki a böngészőből. Ha feldobja az autentikációs ablakot, akkor nyertünk. A sikeres bejelentkezéshez persze kell a működő provider is.

Ha esetleg nem működne a cucc, és még nincs a helyén, akkor az IIS Managerben a Modules panelon adjuk hozzá az installált modulokhoz a CustomBasicAuthentication-t is a legördülő listából.

IIS7 Pass-through Authentication + WebDAV

Miután sikerült beüzemelni a .Net Membership Providert és a Custom Basic Authentication kiegészítést, lehetővé vállt, hogy MySQL-ben tárolt virtuális felhasználóimat minden szolgáltatásnál használhassam. A WebDAV persze megint bekavart..

Amit én szerettem volna az a következő:
1. WebDAV SSL titkosítással
2. Egy központi WebDAV root folder és abban Virtuális mappaként bemappolva a felhasználók Site-jai úgy, hogy a webdav root-hoz és más domainjai alatt lévő tartalomhoz se férjenek hozzá.
Az egyes hosztolt weboldalak elérései így néznének ki:
http://www.host.hu/webdav/domain1.hu
http://www.host.hu/webdav/domain2.hu

Az elképzelés tökéletesen működhetne, de nem ment elsőre a dolog..
A főbb lépések így néztek ki:
1. A host.hu/webdav/domain1.hu - virtuális mappa WebDav Authentication Rule-jai közé hozzáadtam a “test” nevű felhasználót.
2. Adtam neki WebDAV jogokat, innentől kezdve elméletileg van joga a virtuális könyvtár fizikai helyére és annak összes alkönyvtárára WebDAV-on keresztül.
3. Csatlakoztam a “test” nevű felhasználóval és rendben meg is jelent a domain1.hu könyvtár tartalma:

log/                   --        Tue, 20 Jan 2009 09:07:05 GMT
tmp/                   --        Tue, 20 Jan 2009 09:07:13 GMT
www/                   --        Wed, 28 Jan 2009 15:35:31 GMT

A log és tmp könyvtárakkal semmi gond, minden jog érvényesült. Viszont a www-re listázáskor hibát kaptam, nem érvényesültek rá a domain1.hu-ra kiadott jogok. Csak a www-re? Mivan? Miért is?

Mivel az IIS konfigurációja elosztott, több szinten definiálható, ezért amikor egy kérés jön a webszerverhez, ő gyorsan körbenéz minden beállítási szinten: megnézi az applicationHost.config fájlban az alapbeállításokat, érvényesíti, a location tagekben (ha van) a site konfigurációját, érvényesíti, egy szinttel lejjebb, a könyvtárstruktúrában elhelyezett web.config fájlokban keres, érvényesít és halad méglejjebb az almappák web.config-jaihoz, stb, stb.. Hopp! Ez lesz a baj!

Mivel a http://www.host.hu/domain1.hu/www mappa igazábol a szerveren hosztolt domain1.hu site root-ja, az ottani web.config fájlt is érvényesíteni szeretné függetlenül attól, hogy én WebDAV-on keresztül egy másik alkalmazásból hívom meg a könyvtár elemeit. Szeretne hozzáférni a web.config-hoz, de nyilván nem tud, innentől kezdve nagyon egyszerű dolgunk van, hiszen csak azt kell megakadályoznunk, hogy a domain1.hu alkönyvtárait és az azok alatti könyvtárak web.config fájljait is keresse az IIS. A legszebb az egészben, hogy ehhez csak annyit kell tennünk, hogy a domain1.hu virtuális könyvtárához hozzáadjuk az allowSubDirConfig=”false” paramétert az applicationHost.config központi konfigurációs fájlban.

A dolog működik, viszont óriási biztonsági rést üt. Gondolkozzunk el egy picit, hogy hogyan működik a WebDAV. A HTTP protokoll hátán utaznak az infok, a 80-as porton. Az IIS elkülöníti a WebDAV és sima HTTP kéréseket, jogosultságilag is, azzal nincs is gond, hogy a WebDAV jogokat csak a webdav/domain1.hu, webdav/domain2.hu stb.. virtuális mappákra és azok felhasználóira adom ki így megakadályozva, hogy egyik felhasználó a másik cuccai közt bóklásszon.
De ha ezt sima HTTP-n keresztül teszi, akkor autentikáció után a böngészőbe csak a mefelelő elérési utat kell bepötyögnie és bármilyen fájlhoz hozzáfér amit a virtuálsi WebDAV-os mappákkal bemappoltam. Azt mondanán, hogy ez sem gond, hiszen ezt közvetlenül mondjuk a domain1.hu/titok.html-en keresztül közvetlenül is megteheti. Pedig nem. Mivel a web.config fájlokban olyan autentikációs és authorizációs illetve átirányítási utasítások lehetnek, melyek elfednek bitonyos fájlokat a működő aplikációkban, ezért ha mi hatástalanítjuk a allowSubDirConfig-al, szabad az út az ilyen módon védett tartalomhoz. a http://www.host.hu/webdav/ felől érkezve.

Ezért mindenképp meg kell akadályoznunk, hogy a bejelentkezett felhasználó HTTP (nem WebDav) kéréssel elérje a könyvtárakat (persze a saját könyvtárát el kell, hogy érje, hiszen ha HTTP nincs, WebDAV sincs). A megoldás pofon egyszerű és szép is:

1. A webdav/ könyvtárunkat fosszuk meg az Authorization beállításoknál az Allow All-tól. Ezzel megakadályozva, hogy az autentikált felhasználó bármit is elérjen a könyvtáron belül.
2. Osszunk ki egy szinttel lejjebb a webdav/domain1.hu felhasználójának a “test” usernek egy Allow-t.

Kész a shared hosting webdav elérés is. Enjoy!
Felelőséget persze nem vállalok az itt leírtakért, mert csak részben érintem a biztonsági kérdéseket. Ezen kívül rengeteg egyéb követelménynek kell teljesülnie egy biztonságos kiszolgálón.

IIS7 aldomain átirányítás

Az aldomainek (subdomain) leggyakrabban két átirányítási formája létezik: a redirect és a rewrite. Hagyományosan az átirányítás, azaz a rewrite csak annyit tesz, hogy egy 301-es üzenettel egy másik címre “dobja” a böngészőnket, így a böngészőbe írt url is megváltozik. A rewrite, vagyis az “átírás” ezzel szemben elfedi a kiszolgálás helyét. Lássunk két példát és IIS rule kódjaikat:

A böngészőbe ezt írjuk: http://valami.vargapeter.com/index.html
A kiszolgálás valós helye mindkét esetben:  http://vargapeter.com/valami/index.html.

Redirect

Eredmény:  http://domain.hu/valami/index.html

<rule name="aldomain" stopProcessing="true">
     <match url="^(.*)$" ignoreCase="false" />
     <conditions logicalGrouping="MatchAny">
           <add input="{HTTP_HOST}" pattern="^valami.vargapeter.com" />
     </conditions>
     <action type="Redirect" url="http://www.vargapeter.com/valami" redirectType="Permanent" />
</rule>

Rewrite

Eredmény: http://valami.domain.hu/index.html

<rule name="aldomain" stopProcessing="true">
    <match url="(.*)" />
    <conditions logicalGrouping="MatchAll">
        <add input="{HTTP_HOST}" pattern="^valami.vargapeter.com(.*)" />
    </conditions>
    <action type="Rewrite" url="valami/{R:1}" />
</rule>

Fontos, hogy az aldomainek minden esetben konfigurálva legyenek a DNS szervereken és az IIS-ben pedig a webhely (Site) kötéseihez -utálom ezt a szót- (bindings) hozzá legyenek adva.

A Rewrite talán érdekesebb picit, ezért még egy kis regexpel tarkított kódrészletet is bemutatnék, amivel praktikusan kezelhetjük aldomainjeink átirányítását. A szabály lényege, hogy a valami.vargapeter.com domaint a wwwroot/_sub/valami könyvtárra irányítja. Így nem kell öt szabályt létrehoznunk, ha öt domainünk van és külön-külön megadni a valós kiszolgálási helyüket, hanem “rendszerezve” a _sub mappában az aldomain első tagjával megegyező nevű mappa lesz a subwwwroot-juk.

<rule name="SubDomain" stopProcessing="true">
    <match url="(.*)" />
    <conditions logicalGrouping="MatchAll">
        <add input="{HTTP_HOST}" pattern="^(.+).vargapeter.com(.*)" />
    </conditions>
    <action type="Rewrite" url="_sub/{C:1}/{R:1}" />
</rule>