Hlavní navigace

Cocoon v příkladech: Autentizační framework

18. 2. 2004
Doba čtení: 7 minut

Sdílet

Už se jste někdy ve své webové prezentaci či aplikaci potřebovali omezit přístup k některým částem tak, aby se k nim dostal jen autorizovaný uživatel? V tomto dílu si ukážeme, jak to lze realizovat v Cocoonu pomocí autentizačního frameworku.

A nebudete muset ani programovat. Aplikační framework je dostatečně flexibilní, takže jej stačí jen správně nakonfigurovat. Pomocí něj můžete chránit stejným způsobem několik dokumentů tak, aby uživatel po autorizaci měl přístup ke všem. Stejně dobře lze nakonfigurovat více způsobů autorizace, takže každý dokument nebo skupina je chráněná zvlášť. Legitimita uživatelů se ověřuje pomocí tzv. autentizačního resource. To může být takřka cokoliv, ale nejčastěji to bývá relační databáze, XML databáze, LDAP nebo obyčejný XML soubor. Poslední volba se velmi hodí v raných etapách vývoje, kdy databázová část aplikace nemusí být k dispozici.

Jak to pracuje

Autentizační framework obsahuje několik komponent, které lze použít v mapě aplikace. Jsou to zejména akce auth-protect, auth-login,auth-logout a auth-loggedIn. Autentizační manažer spravuje konfigurace jednotlivých handlerů, akce řídí vlastní zpracování HTTP požadavku v rouře. Proces získání dokumentu lze stručně popsat takto:

  1. Uživatel požaduje dokument.
  2. Autentizační framework zkontroluje, zda je dokument chráněn. Pokud ne, uživatel požadovaný dokument obdrží přímo.
  3. Pokud je dokument chráněn, autentizační framework zkontroluje, zda je uživatel znám a zda je autorizován dokument získat. Pokud ano, uživatel obdrží požadovaný dokument.
  4. Pokud není uživatel znám (tj. ještě se nepřihlásil) či autorizován, autentizační framework přesměruje požadavek na jiný dokument podle konfigurace. Například to může být informace o nepovoleném přístupu a formulář pro přihlášení.
  5. Po úspěšném přihlášení lze pokračovat odesláním požadovaného dokumentu.

Vzhledem k flexibilitě Cocoonu je ovšem možné nakonfigurovat libovolný jiný postup.

Příklad

Řekněme, že máme pěknou stránku s důvěrnými informacemi, kterou mohou získat jen uživatelé bfu nebo guest. Stránka by mohla vypadat takto:

protected

Je to zcela běžná HTML stránka (soubor „protected.html“), navíc je zde jen doplnění dynamické informace o přihlášeném uživateli z uživatelské relace (session):

<html>
 <head>
  <title>Chráněná zóna</title>

  <meta http-equiv="content-type"
    content="text/html; charset=utf-8" />
 </head>
 <body>
  [ <a href="login"> přihlášení </a>
  | <a href="protected"> chráněná zóna </a>

  | <a href="do-logout"> odhlášení </a> ]

  <p>
   Přihlášen uživatel
   <b><session:getxml xmlns:session=
      "http://apache.org/cocoon/session/1.0"
      context="authentication"
      path="/authentication/ID"/></b>.
  </p>

  <p>Tato stránka obsahuje tajné informace.</p>
 </body>
</html>

Kromě této chráněné stránky budeme potřebovat stránku s formulářem na přihlášení (soubor „login.html“):

login

Pro tento příklad nám bude stačit jen jméno, ve skutečné aplikaci by bylo vhodné mít i heslo.

Další vhodná (nikoliv však nezbytně nutná) stránka je informace o neúspěšném přihlášení, jejíž kód najdete v souboru „auth_failed.html“. Stránka dále nabízí obdobný formulář pro další pokus o přihlášení:

failed

Všechny stránky mají nahoře odkazy na přihlášení, chráněnou stránku a odhlášení. Dále požadujeme, aby kliknutí na „chráněnou zónu“ zobrazilo opět jen přihlašovací formulář, dokud uživatel nebude úspěšně přihlášen. Naopak pokud je uživatel přihlášen, kliknutí na „přihlášení“ nezobrazí přihlašovací formulář, dokud se uživatel neodhlásí.

Mapa

Protože na stránkách ani jejich definicích není nic zvláštního, podíváme se, jak vypadá mapa aplikace. Žádné neobvyklé deklarace nejsou sice potřeba, je však nutné definovat jeden nebo několik handlerů pro autentizační manažer:

...
<map:pipelines>
 <map:component-configurations>
  <authentication-manager>
   <handlers>
    <handler name="demohandler">
     <redirect-to uri="cocoon:/login"/>
     <authentication
        uri="cocoon:/authenticate"/>
    </handler>
   </handlers>
  </authentication-manager>
 </map:component-configurations>
... 

Výše uvedený fragment mapy konfiguruje handler, který jsme pojmenovali „demohandler“, aby se požadavek na cokoliv, co je chráněno tímto handlerem, přesměroval na stránku s přihlášením této aplikace. Samozřejmě jen pokud již uživatel nebyl úspěšně autorizován. K autentizaci (autorizaci) se použije autentizační resource cocoon:/authenticate. Pseudoprotokol „ cocoon:/“ naznačuje, že se jedná o prostředek aktuální aplikace. Jak uvidíme později, autentizační resource bývá obvykle obyčejná vnitřní roura.

Dále se podívejme, jak vypadá roura, pokud uživatel pošle požadavek na stránku login

...
<map:match pattern="login">
 <map:act type="auth-loggedIn">

   <map:parameter name="handler"
                  value="demohandler"/>
  <map:redirect-to uri="protected"/>
 </map:act>
 <map:generate src="login.html"/>
 <map:transform type="encodeURL"/>
 <map:serialize/>
</map:match>
... 

Akce typu „auth-loggedIn“, která používá náš autentizační handler s názvem „demohandler“, slouží pro řízení toku. Pokud je uživatel již přihlášen, přesměruje jej na chráněnou stránku („protected“). Jinak se zobrazí stránka „login.html“.

Jak probíhá vlastní přihlášení při odeslání formuláře ze stránky „login.html“? Jako akce je ve formuláři uvedeno „do-login“, bude se tudíž zpracovávat touto rourou:

...
<map:match pattern="do-login">
 <map:act type="auth-login">
  <map:parameter name="handler"
                 value="demohandler"/>
  <map:parameter name="parameter_name"
     value="{request-param:username}"/>
  <map:redirect-to uri="protected"/>
 </map:act>
 <map:generate src="auth_failed.html"/>
 <map:serialize/>
</map:match>
... 

Akce „auth-login“ provádí vlastní přihlášení prostřednictvím handleru „demohandler“. Poněkud nejasný může být tento parametr: <map:parameter name="parameter_name" value="{request-param:username}"/>. Slouží k předání jména uživatele do roury autentizačního resource (viz dále), aby uživatel mohl být autorizován či odmítnut. Pokud je přihlášení v pořádku, je uživateli vrácena chráněná stránka, jinak je přesměrován na stránku s informací o neúspěšném přihlášení.

Podobným způsobem je řešeno i odhlašování, které najdete v kompletní mapě aplikace. Tu najdete v archivu auth.zip.

Následující roura zajišťuje vytvoření odpovědi na HTTP požadavek žádající chráněnou stránku „protected“:

...
<map:match pattern="protected">
 <map:act type="auth-protect">
  <map:parameter name="handler"
                 value="demohandler"/>
  <map:generate src="protected.html"/>
  <map:transform type="session"/>
  <map:transform type="encodeURL"/>
  <map:serialize/>
 </map:act>
 <map:redirect-to uri="login"/>
</map:match>
... 

Akce „auth-protected“ slouží pro řízení toku. Pokud je uživatel autorizován, roura generuje SAX události ze souboru „protected.html“, pak následuje transformace „session“, která vkládá v našem případě jméno přihlášeného uživatele. Pokud uživatel není autorizován, je požadavek přesměrován na přihlašovací stránku.

Autentizační resource

V předchozí kapitole chybí vysvětlení, jak se vlastně pozná, zda daný uživatel může získat chráněnou stránku, či nikoliv. Handler pro to používá tzv. autentizační resource. V našem příkladu je to vnitřní roura (tj. lze ji aktivovat pouze z jiných rour aplikace, nikoliv přímo na základě HTTP požadavku klienta):

...
<map:pipeline internal-only="true">
 <map:match pattern="authenticate">
  <map:generate src="users.xml"/>
  <map:transform src="authenticate.xsl">
   <map:parameter name="use-request-parameters"
                  value="true"/>
  </map:transform>
  <map:serialize type="xml"/>
 </map:match>
</map:pipeline>
... 

Naše roura čte XML soubor „users.xml“, transformuje jej pomocí XSLT transformace stylesheetem „authenticate.xsl“ a výsledek vrací ve formátu XML. Handler totiž očekává, že při přihlášení autorizovaného uživatele dostane od autentizačního resource takováto XML data:

<authentication>
 <ID>bfu</ID>
 <role>...</role>
 <data>...</data>
</authentication> 

Úspěšnou autorizaci určuje existence prvku <ID>(ostatní jsou nepovinné). V našem případě tedy soubor „users.xml“ obsahuje seznam autorizovaných uživatelů. XSL stylesheet „authenticate.xsl“ vybere na základě předaného parametru „name“ příslušného uživatele a vytvoří výše uvedený prvek <ID>. Soubor „users.xml“ vypadá takto:

<?xml version="1.0"?>
<authentication>
 <users>
  <user>
   <name>bfu</name>
  </user>
  <user>
   <name>guest</name>
  </user>
 </users>
</authentication> 

Stylesheet najdete v archivu auth.zip.

Roura autentizačního resource nemusí vypadat právě takto – může to být libovolná roura. Není tedy problémem autorizovat uživatele proti SQL databázi nebo LDAP, neboť příslušné generátory a transformátory jsou k dispozici.

CS24_early

Závěr

Chcete-li celý příklad spustit, vytvořte si adresář „auth“ na stejné úrovni, kde jste vytvářeli předchozí aplikace (např. album) a zkopírujte do něj obsah archivu auth.zip. Aplikaci pak spustíte pomocí URL  http://localhost:8888/auth/.

Autentizační framework toho umí mnohem více, než lze popsat v krátkém článku. Zajímají-li vás pokročilejší témata, jako je autorizace pomocí rolí, možnosti správy uživatelů, použití Java třídy jako autentizačního resource atd., najdete je v dobře zpracované dokumentaci.

Byl pro vás článek přínosný?