Archiv pro měsíc: Březen 2010

J2EE – zabezpečení webové aplikace

Tento příspěvek popisuje, jak zabezpečit webovou aplikaci napsanou na platformě Java a běžící na aplikačním serveru GlassFish. Cílem bude zabránit přístupu na vybrané stránky těm uživatelům, kteří nemají přidělenou potřebnou roli.

1. Vytvoření databáze

  • vytvoříme databázi (v zásadě je jedno, jaký typ DB zvolíme, já použil MySQL)
  • tabulka User (Id: email, FK: Grouptable_email)
  • tabulka Grouptable (Id: email, Varchar: groupid)

2. Nastavení aplikačního serveru

  • otevřeme admin consoli
  • v menu vybereme: Configuration → Security → Realms
  • vytvoříme nový Realm:
    • name: Database
    • classname: com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm
    • další property – viz. obrázek

  • v menu vybereme: Configuration → Security a jako default realm vybereme Database
  • dále vytvoříme connection pool (Resources → JDBC → Connection Pools)
  • vytvoříme JNDI, které nazveme „CeltsMysqlDS“ (Resources → JDBC → JDBC Resources)

    3. Vytvoření a nastavení enterprise aplikace

  • např. v prostředí Netbeans IDE vytvoříme enterprise aplikaci
    • J2EE_security (.ear)
    • J2EE_security-ejb (.jar)
    • J2EE_security-war (.war)
  • nastavíme web.xml
    • nastavíme způsob autentifikace
    • nastavíme logovací a chybovou stránku:

    <login-config>
            <auth-method>FORM</auth-method>
            <form-login-config>
                <form-login-page>/login.jsf</form-login-page>
                <form-error-page>/loginError.jsf</form-error-page>
            </form-login-config>
    </login-config>
    

    • nastavíme seznam uživatelských rolí:

    <security-role>
            <description>READWRITE</description>
            <role-name>READWRITE</role-name>
    </security-role>
    <security-role>
            <description>SUPERWRITE</description>
            <role-name>SUPERWRITE</role-name>
    </security-role>
    <security-role>
            <description>ADMIN</description>
            <role-name>ADMIN</role-name>
    </security-role>
    

    • nastavíme security constraint:

    <security-constraint>
            <display-name>Editation</display-name>
            <web-resource-collection>
                <web-resource-name>edit.jsf</web-resource-name>
                <description/>
                <url-pattern>/edit.jsf</url-pattern>
                <http-method>GET</http-method>
                <http-method>POST</http-method>
                <http-method>HEAD</http-method>
                <http-method>PUT</http-method>
                <http-method>OPTIONS</http-method>
                <http-method>TRACE</http-method>
                <http-method>DELETE</http-method>
            </web-resource-collection>
            <auth-constraint>
                <description>vkládat nesmí uživatel read-only</description>
                <role-name>READWRITE</role-name>
                <role-name>SUPERWRITE</role-name>
                <role-name>ADMIN</role-name>
            </auth-constraint>
            <user-data-constraint>
                <description/>
                <transport-guarantee>NONE</transport-guarantee>
            </user-data-constraint>
    </security-constraint>
    

    • Pokud se bude chtít uživatel dostat na stránku /edit.jsf, bude muset mít jednu z definovaných rolí – tedy buď READWRITE, SUPERWRITE či ADMIN.
    • namapujeme role v konfiguračním souboru sun-web.xml (je nutné ho vytvořit ve stejném adresáři, ve kterém je web.xml):

    <sun-web-app error-url="">
      <context-root>/SecurityGUI</context-root>
      <security-role-mapping>
        <role-name>ADMIN</role-name>
        <group-name>3</group-name>
      </security-role-mapping>
      <security-role-mapping>
        <role-name>READWRITE</role-name>
        <group-name>1</group-name>
      </security-role-mapping>
      <security-role-mapping>
        <role-name>SUPERWRITE</role-name>
        <group-name>2</group-name>
      </security-role-mapping>
      <class-loader delegate="true"/>
      <jsp-config>
        <property name="keepgenerated" value="true">
          <description>Keep a copy of the generated servlet class' java code.</description>
        </property>
      </jsp-config>
    </sun-web-app>
    

    • Pokud tedy bude mít uživatel v tabulce “grouptable” nastavenou hodnotu “groupid” na “1”, přidělí mu aplikace po zalogování roli “READWRITE”.
    • Nyní jsme zprovoznili zabezpečení naší testovací aplikace. J2EE nám samozřejmě také umožní zjistit, jaký klient je právě zalogovaný. Na úrovni webové aplikace to zjišťujeme následujícím způsobem (následující funkce vrátí username zalogovaného uživatele, případně null pro nezalogovaného uživatele):

    public String getLoginName() {
      Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
      if (principal == null) {
        return null;
      } else {
        return principal.getName();
      }
    }
    

    • Na úrovni aplikační vrstvy (v EJB), postupujeme takto:
      vytvoříme referenci na context

      @Resource
      SessionContext context;
      

      v mětodě dále:

      Principal principal = context.getCallerPrincipal();
      

    • Chceme-li, aby J2EE zajistilo, že se některá funkce bude spouštět pouze v případě, že má uživatel přiřazenou některou roli, vytvoříme před metodou anotaci @RolesAllowed:

    @RolesAllowed("manager")
    public Country getCountryByIso(String iso) { ... }
    

    • Chceme-li v metodě testovat, zda má uživatel přiřazenou některou roli vytvoříme anotaci @DeclareRoles před třídou:

    @Stateless
    @DeclareRoles({"manager", "manager2"})
    public class CommonDAOBean implements CommonDAOBeanLocal { … }
    

    • poté je možné v metodě použít:

    context.isCallerInRole("manager");
    

    • Pokud bychom na začátku nedeklarovali role, nastala by výjimka.

    Sun Certified Java Programmer

    Tak jsem se zúčastnil mého prvního testu na certifikaci. A protože o tom tady píšu, tak je jasné, že jsem ho i udělal :-) Konkrétně šlo o Sun Certified Programmer for the Java Platform, Standard Edition 6 (CX-310-065).

    Vzhledem k tomu, že jsem nevěděl do čeho jdu, tak jsem se snažil ve chvilkách volného času učit. Pro přípravu je bezvadná, i když často zbytečně podrobná, tato knížka http://www.amazon.com/SCJP-Certified-Programmer-Java-310-065/dp/0071591060/ref=sr_1_1?ie=UTF8&s=books&qid=1269886588&sr=1-1 Na konci každé kapitoly je seznam nejdůležitějších znalostí a hlavně ukázkové příklady.

    Když to teď porovnám s těmi v reálném testu, tak musím říct, že v té knížce mi připadaly mnohem zákeřnější.
    Například nějaký složitější zdrojový kód a vy máte určit, co bude jeho výsledkem. No a odpověď byla, že to nepůjde zkompilovat, protože tam chybí jeden import. Na druhou stranu vás to aspoň vycvičí v pozornosti, což se mi několikrát během ostrého testu hodilo.

    No, abych to uzavřel, velká část otázek mně přišla nesmyslná. Týkaly se totiž toho, co za vás zkontroluje kompilátor. Na druhou stranu, jsem se během studia občas dozvěděl něco nového a také už snad nebudu muset tak často hledat v dokumentaci :-).

    Také je dobré, že se na konci testu dozvíte, jak jste dopadli v jednotlivých oblastech. Detailní popis zkoušených oblastí najdete na této stránce http://in.sun.com/training/catalog/courses/CX-310-065.xml