Daily Archives: 2007.02.23. 18:06

CardSpace és ASP.NET AJAX 3: Adatok bekérése és elküldése

(Aki esetleg lemaradt volna a bevezetőről, ezen a címen találja meg.)

Hozzunk létre Visual Studioban egy új ASP.NET AJAX-Enabled Web Site-ot, méghozzá IIS-en http-n kereszül, nem pedig File System locationnel. Ehhez rendszergazdai jogokkal kell indítani a Studiot! Ha később szeretnénk debuggolni, akkor az Internet Information Services MMC snap-inben engedélyezzük a Windows Authenticationt az így létrehozott mappánkra.

A kártya adatainak bekérése nem ördöngősség, mindössze egy OBJECT tag kell hozzá, amiben megadjuk az ún. claimeket, azaz tudatjuk a klienssel és a felhasználóval, hogy milyen adatokat várunk tőle, valahogy így:

<object name="xmlToken" id="objIdentitySelector" style="visibility:hidden;">
  <param name="tokenType" 
         value="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" />
  <param name="requiredClaims" 
         value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname 
                http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname 
                http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress 
                http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" />
</object>

A sok claim közül a legfontosabb a privatepersonalidentifier, ez az a kliens oldali azonosító, amire vadászunk. A visibility stílust azért állítottam hiddenre, hogy ne jelenjen meg a böngészőben kis piros kocka az OBJECT tag helyén és ne is foglaljon helyet.

Ezen kívül az OBJECT tag TYPE attribútumát application/x-informationcard értékre kell állítanunk, de ezt inkább JavaScriptből fogjuk megtenni. Az objektum akkor jeleníteni meg a kártya bekérő ablakot, ha valaki hozzáfér a value tulajdonságához, akkor viszont azonnal és mindig. Ez elég kellemetlen, hiszen az oldal elpostázásakor a value értéke mindenképpen kiolvasódik, ami nagyon zavaró, hiszen egyáltalán nem biztos, hogy emiatt történik postback. Gondoljunk csak arra, hogy ezt a funkcionalitást a login oldalon fogjuk elhelyezni, a már működő Login kontroll alternatívájaként. Az alapértelmezett viselkedés az lenne, hogy amikor a felhasználó megadja a nevét és a jelszavát és rákattint a bejelentkezés gombra, még a rendszer az arcába tolja a kártya kiválasztó (ún. Identity Selector) ablakot. Ezen nekem csak úgy sikerült felülkerekednem, hogy a viselkedést meghatározó TYPE attribútumot akkor állítjuk be, amikor szükséges.

Tegyünk az oldalra egy linket, ami majd meghívja a szükséges JavaScriptet:

    <a href="javascript: selectInfoCard();">Kártya kiválasztása</a>

A meghívott függvényben az a feladatunk, hogy egy rejtett mezőbe átmásoljuk az Identity Selector által visszaadott XML-t, ugyanis a rejtett mező tartalmát sokkal könnyebben tudjuk elérni szerver oldalon, mint az OBJECT tartalmát. Ehhez persze kell egy rejtett mező, amiben az ún. XML Token fog utazni:

    <input id="hidIdentityToken" type="hidden" runat="server" />

A rejtett mező és az objektum elérését legegyszerűbben az ASP.NET AJAX-ban megjelenő $get függvénnyel tehetjük meg:

    <script language="javascript" type="text/javascript">
        function selectInfoCard()
        {
            var oIS = $get( "objIdentitySelector" );
            var hIT = $get( "hidIdentityToken" );
            oIS.type="application/x-informationcard";
            hIT.value = oIS.value;
            $get( "form1" ).submit();    
        }
    </script>

Ezzel azért van legalább 2 probléma:

Az első, hogy ha mindezt egy kontrollban valósítjuk meg, akkor az objektumok elérése nem lesz ilyen egyszerű, a rejtett mező szerver kontroll lévén más azonosítót fog kapni. Ezt persze szerver oldalon le tudjuk kérdezni és ki tudjuk vezetni egy property-be:

    protected string HiddenFieldClientName
    {
        get
        {
            return this.hidIdentityToken.Name;
        }
    }

A property-t pedig be tudjuk drótozni a JavaScriptbe és a korábbi második sort kicserélhetjük erre:

    var hIT = $get( "<%= HiddenFieldClientName %>" );

A második problémát szintén az ASP.NET fogja okozni. Mivel az Identity Selector kontroll XML-t ad vissza és mi azt akarjuk a szerverre postázni, ezért "A potentially dangerous Request.Form value was detected from the client" hibaüzenetet fogunk kapni. A mezei megoldás persze az, hogy letiltjuk a validálást szerver oldalon, de mivel éppen olyan kódot írunk, amit majd a login oldalon is fogunk használni, ez nem túl bölcs lépés lenne.

Ehelyett sokkal szebb feladat, hogy megírjuk a Server.HtmlEncode függvényt kliens oldalra, amivel szépen hátéemelesítjük az XML, hogy aztán majd szerver oldalon egy csapásra vissza tudjuk alakítani. Sajnos ezt nekünk kell megírnunk, mert az AJAX Library nem tudja (pedig illene neki). Sokféle megoldás közül választhatunk, én úgy döntöttem, hogy a String osztály funkcionalitását terjesztem ki egy újabb függvénnyel (gyanítom, hogy ez nem tökéletes, de eddig működött nálam):

    String.prototype.htmlEncode = function() {
        s = this;
        a = s.split( "&" ); s = a.join( "&amp;" );
        a = s.split( "<" ); s = a.join( "&lt;" );
        a = s.split( ">" ); s = a.join( "&gt;" );
        a = s.split( '"' ); s = a.join( "&quot;" );
        return s;    
    }

Ezt felhasználva módosíthatjuk a selectInfoCard() metódust:

    hIT.value = new String( oIS.value ).htmlEncode();

Ha eddig ügyesek voltunk, akkor szerver oldalon egyetlen sorral el tudjuk érni a kártyát reprezentáló XML tokent:

    string xmlToken = this.Server.HtmlDecode( this.hidIdentityToken.Value );

Ezzel tehát megoldottunk a bejelentkezéshez szükséges adatok elkérését és elküldését. De ez persze nem fog mindig működni… folyt. köv. 

 

Technorati tags: , ,

Advertisements

CardSpace és ASP.NET AJAX 2: A terep előkészítése

(Aki esetleg lemaradt volna a bevezetőről, ezen a címen találja meg.)

A webszerver előkészítése

A legelső feladatunk, hogy létre kell hoznunk egy SSL-es webhelyet. Ehhez IIS-re lesz szükségünk, tehát aki eddig hozzám hasonlóan a Visual Studio beépített fejlesztői webszerverét használta, most egy kicsit búcsúzzon el tőle és kapja elő az Add/Remove Programsot és lökje fel az IIS-t a gépére.

Ha az IIS telepítést megelőzte az ASP.NET telepítése, akkor következő lépésként érdemes beregisztrálni az ASP.NET-et az IIS-be, amire az aspnet_regiis /i az ideális eszköz (megtalálható a %FrameworkDir%v2.0.50727 mappában).

Az SSL-hez szükséges tanúsítvány létrehozását az IIS 6 Resource Kitben található SelfSSL eszközre bízzuk. Az egész csomag ingyenesen letölthető, aki nem akar sokmindent feltelepíteni, válassza ki csak ezt a telepítőből. A mindössze 48 KB-os parancssori alkalmazás elérhető a Start menüből, ami lényegében egy command prompt ablak a %ProgramFiles%IIS ResourcesSelfSSL mappára.

Ha paraméterezés nélkül indítjuk, akkor SSL-esíti a localhostunkat, ami nálunk most nem egészen jó. A végső alkalmazásunkat valószínűleg interneten keresztül szeretnénk publikálni, azaz teljes FQDN-nel http://www.akarmi.hu formában, amit a böngészők az Internet Zónába sorolnak. Ha azt szeretnénk, hogy a fejlesztői környezetünk is ebben legyen, akkor pontnak kell lennie a hostname-ben és természetesen a tanúsítványban. Tehát használjuk a /N paramétert, valahogy így (a /T rögtön a trusted root CA-k közé is beteszi a tanúsítványt, ami most fontos nekünk):

    selfssl.exe /N:CN=bambus.local /T

A programot mindenképpen rendszergazdai jogokkal indítsuk, sokféle hibaüzenettől kímélhetjük meg magunkat! Ha sikerült "Failed to build the subject name blob: 0x80092023" hibaüzenetet kapni, akkor kifelejtetted a CN=-t!

Névfeloldás konfigurálása

A bambus.local-t természetesen nem fogja megtalálni a böngésző, hacsak nem segítünk neki azzal, hogy felvesszük a hosts fájlba ezt a rekordot. Irány a Notepad és a %WinDir%System32Driversetchosts fájlba vegyük fel a következő rekordot:

    127.0.0.1	bambus.local

Ha ez így megvan, akkor teszteljük az SSL működését például azzal, hogy böngészőben megnyitjuk a https://bambus.local/print.gif útvonalat. Adig etessük a böngészővel a tanúsítványokat, amíg már nem jelez hibát!

Ezek után úgy tűnik érdemes újraindítani az egész gépet a Windows CardSpace szolgáltatást (net stop idsvc), különben később egy barátságos, ám semmitmondó "Windows CardSpace encountered an error when verifying the identity of the site and cannot continue. To close Windows CardSpace, click OK. To temporarily prevent Windows CardSpace from starting, click Disable." üzenet fog megjelenni a kártya kiválasztásakor.

Tanúsítványok előkészítése

Az előző lépésben használt SelfSSL létrehozott egy gyönyörű tanúsítványt, és azt be is konfigurálta az IIS-ben. Erre a tanúsítványra sajnos még nekünk is szükségünk lesz, amikor a kliens által elküldött kártya információkat próbáljuk kibogarászni szerver oldalon. Fájdalom, de alapértelmezés szerint a webalkalmazást futtató ASPNET (XP-n) vagy Network Service (Windows Server 2003-on) felhasználónak nincs joga hozzáférni ehhez a tanúsítványhoz.

A bátrabbak elindíthatják a Certificates MMC snap-int, megnyitva a Local Computer tanúsítványtárát látni fogjuk a szóban forgó tanúsítványt, csak éppen a hozzáférést nem tudjuk szabályozni rajta.

A tanúsítványokat a fájl rendszer ACL-jei védik, mégpedig a %AllUsersProfile%Application DataMicrosoftCryptoRSAMachineKeys mappában. Ha vadulni szeretnénk, akkor persze állítgathatjuk itt az ACL-eket, de ha sebészi beavatkozást szeretnénk végezni, akkor célszerszámra lesz szükségünk. A WseCertificate3.exe a WSE 3.0 része, és telepítés után a C:Program FilesMicrosoft WSEv3.0Tools mappában találjuk meg mind a 40 KB-ját.

Természetesen ezt az eszközt is rendszergazdai jogokkal indítsuk, különben "Keyset does not exist" hibaüzenetet kapunk. Ugyanezt a hibaüzenetet kapnánk később is, ha a szerver oldali kódunknak nincs joga elérni egy tanúsítványt.

Válasszuk a Local Computer locationt és a Personal store-t, majd kattintsunk az alsó View Private Key File Properties gombra, ahol a szokásos ablakban adjunk legalább Read & Execute jogot az ASPNET vagy a Network Service felhasználói fióknak.

Mind a SelfSSL.exe, mind pedig a WseCertificate3.exe fájlt érdemes eltenni magunknak, hiszen ezekre még akkor is szükségünk lesz, amikor az alkalmazásunkat a végleges szerverre telepítjük!

Folyt. köv.

 

Update: nem kell az egész gépet újraindítani, elég a Windows CardSpace szolgáltatást.

Technorati tags: , ,

CardSpace és ASP.NET AJAX 1: Bemelegítés

Aki körbekattintgatott már az új Vistáján vagy alaposan megnézi, mi kúszik a gépére a Windows Update-ről, annak biztosan feltűnt egy új ikon a Vezérlőpulton. A Windows CardSpace, vagy gyerekkori nevén InfoCard, bizony még a Workflow Foundationnél is mostohább része a .NET Framework 3.0-nak, róla ugyanis még összesen nem beszélt annyit senki, mint a három Foundation bármelyik apró részletéről.

Az egésznek az a célja, hogy egyszerűsítse a felhasználók számára az egyes webhelyeken használt identitások kezelését és persze lehetőleg biztonságosabbá is tegye azt, miközben nem megy bele platformfüggő és csúnya kapitalista, monopolista, erőfölénnyel visszaélő zsákutcákba, ami miatt aztán egy remek alapötlet kudarcba fulladna (ld. Passport). Fontos változás az eddigiekhez képest, hogy a rendszer nem azon alapul, hogy valamilyen központi szerveren tárolódnak az indentitásunkhoz kapcsolódó adataink, hanem a saját gépünkön és mi választhatjuk ki, hogy éppen akarjuk-e valamelyiket használni vagy sem és közben egyértelműen látjuk, hogy milyen adatokat osztunk meg az adott webhellyel.

Akinek sikerült felkelteni az érdeklődését, bőven olvashat még róla a közösségi oldalán, az MSDN-en, vagy akár a Wikipedián. Ennek a cikknek (és a folytatásainak) az a célja, hogy segítsen beépíteni a CardSpace alapú hitelesítést webalkalmazásainkba, ugyanis azt vettem észre, hogy a weben található példák sok sebből véreznek.

A teendők szépen sorban:

  1. Bemelegítés: ezt olvasod most, csak hogy lássuk, mibe is vágjuk a fejszénket.
  2. A környezet előkészítése: IIS, tanúsítványok, SSL, ACL-ek.
  3. Adatbekérés és elküldés megvalósítása weboldalon: itt lesz egy kis Microsoft AJAX, hogy kevesebb JavaScriptet kelljen írnunk, mert a ValidateRequesttel és a HTML encodinggal lesz egy adag szívás.
  4. AJAX ide vagy oda, külön részben küzdünk a böngészőfüggőséggel, ha esetleg valaki hiányolná.
  5. Adatok feldolgozása szerver oldalon: titkosított XML értelmezése szinte élményszámba megy, előre lehet örülni neki.
  6. Bejelentkezés megvalósítása: ez már szinte sétagalopp, még ha a Membership providert meg is kell kerülni.

A dolog lényege igen röviden:

Kell készítenünk egy olyan SSL-es weblapot, amelyen JavaScripttel felizgatunk egy OBJECT tag-et, hogy az jelenítse meg a kártya kiválasztó ablakot (ami nagyon hasonló a Vezérlőpultos applethez). Ez a kontroll XML-t fog nekünk visszaadni, amit "HTML enkódolva" el kell küldenünk a szerverre, hogy ott aztán a megfelelő XML tageket tanúsítványok segítségével értelmezzük. Ennek a nagy küzdelemnek az eredménye az lesz, hogy átmegy egy ID a kliensről a szerverre, ami egyedi a kártya-webhely párosra nézve, tehát mi szerver oldalon elhihetjük, hogy ez az ID a világon csak egyetlen felhasználónak áll a rendelkezésére. Ezt eltesszük egy adatbázisba, hogy amikor bejelentkezéskor felhasználó név és jelszó helyett ezt kapjuk meg, akkor megnézzük, hogy ott van-e és ha igen, akkor tudjuk, hogy melyik felhasználóhoz tartozik, ugyanis az kell ahhoz, hogy a Membership providerrel elhitessük, hogy a felhasználó már azonosította magát.

Vonzó, nem? smile_tongue

Folyt. köv.

 

Technorati tags: , ,