wtorek, 23 lutego 2010

JSF + Tomcat 6 + Eclipse - Hello World

Konfiguracja Apache Tomcat 6
Zaczniemy od przygotowani środowiska pracy. Potrzebujemy oczywiście zainstalowanego Tomcat'a oraz pliku jstl-1.2.jar. Plik jar ściągamy i kopiujemy do katalogu tomcat_home\lib.

Pierwsza aplikacja Java Serwer Faces
Uruchamiamy eclipse i tworzymy nowy Dynamic Web Project.

Wpisujemy nazwę naszego produktu i ustawiamy:

  • Target runtime: na Apache Tomcat v6.0
  • Dynamic web model version: na 2.5
  • Configuration: na JavaSerwer Faces v1.2 Project

Wszystko powinno wyglądać mniej więcej tak:

Następnie klikamy Next > do momentu aż pojawi się okienko z ustawieniami JSF. Klikamy na Download library.
Po krótkiej chwili pojawi się okienko z dostępnymi bibliotekami do JSF. Wybieramy JSF 1.2 (Apache MyFaces) i klikamy Next >.
Akceptujemy licencję i klikamy Finish.

Dodajemy do URL Mapping Patterns: *.jsf.

Jeśli wszystkie kroki wykonaliśmy prawidłowo wszystko powinno wyglądać tak:


Właśnie stworzyliśmy strukturę projektu. Jak pewnie już zauważyliście jest to normalny Web Projekt z katalogiem Web Content w którym znajduje się katalog WEB-INF z plikiem web.xml. Jest jednak mała różnica, w katalogu WEB-INF znajduje się plik o nazwie faces-config.xml. Jest to plik gdzie znajduje się cała konfiguracja odnośnie JSF. Na razie plik ten jest pusty. 
Zaczniemy od stworzenia prostej klasy zarządzającej treścią strony, tzw. bean, warto zwrócić tutaj uwagę że klasa powinna być napisana zgodnie z prostymi zasadami nazewniczymi dla metod zwracających (getNazwaZmiennej) i ustawiających (setNazwaZmiennej) . W katalogu src tworzymy pakiet com.blogspot.mkorwel.jsf a w nim klasę MyBean. Klasa będzie posiadać funkcję która zwróci nam napis "Hello World !!!".

package com.blogspot.mkorwel.jsf;


/**
 * 
 * @author mkorwel
 * 
 */
public class MyBean {


  private String hello = "Hello World !!!";


  public String getHello() {


   return this.hello;
  }

}

Żeby klasę MyBean móc wykorzystywać w JSF musimy dodać ją w faces-config.xml. Otwiera plik XML na zakładce ManagedBean,


zaznaczamy w lewym okienku session i klikamy Add.


Klikamy przycisk Browse... i wybieramy klasę com.blogspot.mkorwel.jsf.MyBean.


W tym momencie możemy już kliknąć Finish. Zapisujemy wprowadzone zmiany i zabieramy się do stworzenia podstawowego widoku, który wyświetli nam napis "Hello World !!!" z klasy MyBean.
W katalogu WebContent tworzymy hello.jsp w którym wyświetlimy napis. Plik u mnie wygląda tak:
<%@ taglib prefix="f"  uri="http://java.sun.com/jsf/core"%>
<%@ taglib prefix="h"  uri="http://java.sun.com/jsf/html"%>
<html>
<head>
<title>JSF Tutorial</title>
</head>
<body>
<f:view>
<h:outputText value="#{myBean.hello}"></h:outputText>
</f:view>
</body>
</html>
W pierwszych dwóch linkach naszej strony definiujemy dwa zbiory znaczników.
Wszystkie znaczniki technologii JSF znajdują się pomiędzy znacznikiem <f:view>.
Znacznik <h:outputText value="#{myBean.hello}"></h:outputText> wyświetla tekst na ekranie, w atrybucie value precyzujemy skąd ma być wzięta treść. W naszym przypadku będzie to klasa która w pliku faces-config.xml nazywa się myBean (czyli klasa com.blogspot.mkorwel.jsf). Po kropce definiujemy metode typu get która ma się wykonać, w naszym przypadku będzie to metoda getHello(), która zwróci "Hello World !!!".

W tym momencie cała aplikacja jest gotowa, wiec możemy ją zdeployować na serwerze. Stronę możemy obejrzeć pod adresem http://localhost:8080/JSFHelloWorld/faces/hello.jsp , http://127.0.0.1:8080/JSFHelloWorld/faces/hello.jsphttp://localhost:8080/JSFHelloWorld/hello.jsf, lub http://127.0.0.1:8080/JSFHelloWorld/hello.jsf.

piątek, 19 lutego 2010

Eclipse + SVN

Jeśli zaczynamy jakiś projekt grupowy i zdecydowaliśmy się pisać go pod Eclipem, to warto zainteresować się również SVN (Subversion), który jest prostym i skutecznym systemem kontroli wersji. Dzięki temu bez problemu będziemy mogli wymieniać się plikami, każdy będzie miał dostęp do aktualnej i działającej wersji naszego projektu.

Instalujemy wtyczkę subclipse.

Otwieramy eclipsa i wchodzimy w Help -> Install New Software ...

Po kliknięciu w przycisk Add... wyskakuje małe okienko, w którym proszeni jesteśmy o podanie nazwy (Name:) oraz lokalizacji (Location:) wtyczki jaką chcemy zainstalować. My instalujemy wtyczkę do SVN, dlatego w pierwszy polu wpisujemy svn, w drugim podajemy lokalizację, czyli http://subclipse.tigris.org/update_1.6.x.


Klikamy w OK, a w nowo otwartym oknie zaznaczamy wszystkie checkboxy i wciskamy Next >.


Teraz instalator podsumowuje listę tego co chcemy zainstalować. Klikamy jeszcze raz Next >, po czym akceptujemy licencję i kliknąć przycisk Finish. Teraz musimy chwilę poczekać, jeśli podczas instalacji pojawia się jakieś ostrzeżenia, to ignorujemy je. Jeśli wszystko przebiegnie bez komplikacji Eclipse będzie musiał uruchomić się ponownie. Po restarcie wtyczka subclipse powinien już działać. Możemy to sprawdzić klikając w Window -> Open Perspective -> Other ... i w liście perspektyw powinna znajdować się SVN Repository Exploring.



czwartek, 18 lutego 2010

JAAS - podstawy

Co to jest JAAS?
JAAS czyli Java Authentication and Authorization Service, jest to narzędzie wbudowane do Javy 1.4 i nowszej, które pozwala na łatwą autoryzacje i uwierzytelnianie użytkownika.

Aplikacja
Zaczniemy od zrobienia prostej aplikacje, którą później zabezpieczymy przy pomocy JAAS'a tak, aby osoba przeglądająca naszą witrynę musiała potwierdzić że jest w gronie osób które mogą przeglądać treść danych podstron.
Moja prosta aplikacja wygląda tak:

Do stworzenia mojej aplikacji skorzystałem z popularnego edytora Eclipse. Projekt nazwałem JAASHelloWorld. Widzimy że cała aplikacja składa się z trzech podstron:
  • admin/index.jsp - strona do której będzie miał dostęp tylko administrator
  • user/index.jsp - strona do której będzie miał dostęp zalogowany użytkownik i administartor
  • index.jsp - strona główna do której mają dostęp wszyscy
Aplikacja będzie uruchomiana na popularnym serwerze aplikacji JBoss.

Panel logowania
Bardzo ważną rzeczą jest formularz logowania, dzięki któremu użytkownik będzie mógł potwierdzić swoją tożsamość. Dlatego zaczniemy od stworzenia nowego katalogu login a w nim strony login.jsp. Strona zawiera prosty formularz z dwoma polami i przyciskiem. Formularz musi zawierać trzy bardzo istotne elementy:
  • akcję formularza ustawiamy na j_security_check
  • pole login zawiera atrybut name z wartością j_username
  • pole hasło zawiera atrybut name z wartością j_password
U mnie plik ten wygląda:
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 <title>Login</title>
 </head>
 
 <body>
 
  <form method="post" action="j_security_check">
   <div>
    Login:
    <input type="text" name="j_username" />
   </div>
   
   <div>
    Hasło:
    <input type="password" name="j_password"/>
   </div>
   
   <div>
    <input type="submit" value="LOGIN" />
   </div>
  </form>
 
 </body>
</html>

Potrzebujemy jeszcze strony na którą zostaniemy przekierowani w razie błędnego logowania. Do tego celu tworzymy stronę login/login_err.jsp która będzie zawierać komunika o nieudanym logowaniu. U mnie wygląda to tak:
<html>
 <head>
  <title>Login Error</title>
 </head>
 
 <body>
  <div>Logowanie się nie powiodło. Spróbuj jeszcze raz.</div>
 </body>
</html>

Po wykonaniu tego kroku aplikacja wygląda tak:


Baza danych
Następnym krokiem jakim się zajmiemy jest stworzeniem bazy danych. Skrypt który to zrobi wygląda tak:

CREATE TABLE users (
 login VARCHAR(20),
 password VARCHAR(100)
);

CREATE TABLE user_roles (
 login VARCHAR(20),
 rolename VARCHAR(20)
);

Pierwsza tabela users przechowuje nazwy użytkowników (login) i hasła (password) do ich kont.
Druga tabela user_roles przechowuje nazwę użytkownika (login) i nazwę roli (rolename) do której użytkownika należy. Zgodnie z polityką bezpieczeństwa wszystkie hasła przechowywane w bazie danych muszą być szyfrowane. Tak będzie i u nas, dlatego przy pomocy pierwszej strony jaką udało mi się znaleźć w
wyszukiwarce google.com, pod hasłem: "md5 generator" szyfrujemy hasła.
Tak wiec po zaszyfrowaniu haseł admin i user uzyskujemy wyniki:
  • admin = 21232f297a57a5a743894a0e4a801fc3
  • user = ee11cbb19052e40b07aac0ca060c23ee

INSERT INTO users VALUES('admin','21232f297a57a5a743894a0e4a801fc3');
INSERT INTO user_roles VALUES('admin','admin');
INSERT INTO users VALUES('user1','ee11cbb19052e40b07aac0ca060c23ee');
INSERT INTO user_roles VALUES('user1','user');

Konfiguracja JBoss i JAAS
Nadszedł czas na najważniejszą części naszej konfiguracji. Na początek stworzymy DataSource który będzie wskazywał JBoss'owi jakiej bazy należy użyć. JBoss wraz z samym serwerem udostępnia przykładowe pliki konfiguracyjne, które znajdują się w katalogu jboss_home\docs\examples. Zgodnie z zasadą "nie rób więcej niż musisz" wchodzi do tego
jboss_home\docs\examples\jca i kopiujemy plik z nazwą nazwa_bazy-ds, u mnie mysql-ds do katalogu jboss_home\server\default\deploy. Plik ten oczywiście musimy delikatnie zmodyfikować, dlatego otwieramy go i zmieniamy wartości elementów:
  • <jndi-name> - określa nazwę naszego DataSource'a
  • <connection-url> - lokalizacja bazy danych, my używamy MySQl ktory działa pod adresem localhost/nazwa_bazy_danych
  • <user-name> - nazwa użytkownika w bazie danych
  • <password> - hasło do bazy danych
U mnie plik ten po zmodyfikowaniu wygląda tak:
<?xml version="1.0" encoding="UTF-8"?>

<!-- $Id: mysql-ds.xml 41017 2006-02-07 14:26:14Z acoliver $ -->
<!-- Datasource config for MySQL using 3.0.9 available from:
http://www.mysql.com/downloads/api-jdbc-stable.html
-->

<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/testdb</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password>mysql</password>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<!-- should only be used on drivers after 3.22.1 with "ping" support
<valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLValidConnectionChecker</valid-connection-checker-class-name>
-->
<!-- sql to call when connection is created
<new-connection-sql>some arbitrary sql</new-connection-sql>
-->
<!-- sql to call on an existing pooled connection when it is obtained from pool - MySQLValidConnectionChecker is preferred for newer drivers
<check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql>
-->

<!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>

Używamy bazy danych MySQL, dlatego potrzebujemy jeszcze connector do bazy danych. Plik ten można ściągnąc z ofincjalne strony MySQL , a po rozpakowaniu skopiować do katalogu jboss_home\server\default\lib.

Wrcamy ponownie do katalogu jboss_home\server\default\deploy i tworzymy w nim plik jboss-service.xml. Plik ten będzie zawierał informacje, gdzie JAAS ma szukać informacji na temat loginu, hasła i grupy do jakiej użytkownik należy. U mnie plik ten wygląda tak:
<?xml version="1.0" encoding="UTF-8"?>
<server>
 <mbean code="org.jboss.security.auth.login.DynamicLoginConfig"
  name="jboss.seminarium:name=seminarium.login,service=DynamicLoginConfig">

  <attribute name="PolicyConfig" serialDataType="jbxb">
   <jaas:policy
    xsi:schemaLocation="urn:jboss:security-config:4.1 resource:security-config_4_1.xsd"
    xmlns:jaas="urn:jboss:security-config:4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <jaas:application-policy name="my-auth">
     <jaas:authentication>
      <jaas:login-module
       code="org.jboss.security.auth.spi.DatabaseServerLoginModule"
       flag="required">
       <jaas:module-option name="dsJndiName">java:/MySqlDS</jaas:module-option>
       <jaas:module-option name="principalsQuery">
        select u.password from users u where u.login = ?
</jaas:module-option>
       <jaas:module-option name="rolesQuery">
        select r.rolename, 'Roles' from user_roles r, users u
        where u.login = ? and u.login = r.login
</jaas:module-option>
       <jaas:module-option name="hashAlgorithm">MD5</jaas:module-option>
       <jaas:module-option name="hashEncoding">hex</jaas:module-option>
       <jaas:module-option name="hashCharset">UTF-8</jaas:module-option>
      </jaas:login-module>
     </jaas:authentication>
    </jaas:application-policy>
   </jaas:policy>
  </attribute>
  <depends optional-attribute-name="LoginConfigService">
   jboss.security:service=XMLLoginConfig
</depends>
  <depends optional-attribute-name="SecurityManagerService">
   jboss.security:service=JaasSecurityManager
</depends>
 </mbean>
</server>

Krótko powiem co zawierają główne elementy powyższego pliku:
  • <jaas:application-policy> - atrybut name zawiera nazwę dla JAAS'a
  • <jaas:module-option name="dsJndiName"> - wartością tego elementu jest nazwa DataSource'a
  • <jaas:module-option name="principalsQuery"> - wartością tego elementu jest zapytanie select wskazujące na hasło użytkownika
  • <jaas:module-option name="rolesQuery"> - wartością tego elementu jest zapytanie select wskazujące na nazwę roli użytkownika
Wracamy teraz z powrotem do aplikacji. W katalogu WebContent\WEB-INF tworzymy plik jboss-web.xml. U mnie plik ten wygląda tak:
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE jboss-web PUBLIC
"-//JBoss//DTD Web Application 2.4//EN"
"http://www.jboss.org/j2ee/dtd/jboss-web_4_0.dtd">

<jboss-web>
<security-domain>java:/jaas/my-auth</security-domain>
</jboss-web>

Plik ten zawiera element <jboss-web> w którym znajduje się element <security-domain> zawierający nazwę dla JAAS'a którą ustalilismy w pliku jboss-service.xml.
Ostatnim plikiem jaki musimy zmodyfikować jak plik WebContent\WEB-INF\web.xml. W tym pliku ustawiamy:
  • jakie katalogi (strony) są zablokowane dla niezalogowanych użytkoników
  • jakie role obsługiwane są w naszej aplikacji (u mnie jest to user i admin)
  • gdzie znajduje się formularz do logowania

U mnie plik ten po modyfikacji wygląda tak:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 <display-name>JAASHelloWorld</display-name>
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>
 
 <security-constraint>
  <web-resource-collection>
   <web-resource-name>Restricted to user</web-resource-name>
   <url-pattern>/user/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
   <role-name>user</role-name>
   <role-name>admin</role-name>
  </auth-constraint>
 </security-constraint>

 <security-constraint>
  <web-resource-collection>
   <web-resource-name>Restricted to Admin</web-resource-name>
   <url-pattern>/admin/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
   <role-name>admin</role-name>
  </auth-constraint>
 </security-constraint>

 <login-config>
  <auth-method>FORM</auth-method>
  <realm-name>my-auth</realm-name>
  <form-login-config>
   <form-login-page>/login/login.jsp</form-login-page>
   <form-error-page>/login/login_err.jsp</form-error-page>
  </form-login-config>
 </login-config>

 <security-role>
  <description>Typowy uzytkownik systemu</description>
  <role-name>user</role-name>
 </security-role>

 <security-role>
  <description>Administrator systemu</description>
  <role-name>admin</role-name>
 </security-role>
 
</web-app>

To teraz krótki opis, co znajduje się w powyższym pliku.
Jak można zauważyć, w pliku wydzielone są trzy główne elementy: <security-constraint>, <login-config> i <security-role>. Element <security-constraint> zawiera informacje o blokowanych zasobach, oraz o tym jakie grupy użytkowników mają dostęp do informacje zawartych na tych stronach. Element <login-config> zawiera informacje o rodzaju uwierzytelniania (<auth-method>) oraz o formularzu który ma się wyświetlić w razie odniesienia się do zablokowanych zasobów, w celu sprawdzenia czy użytkownik ma wystarczające prawa do oglądania treści zawartych na stronie. Przy konfiguracji JAAS'a ustawiamy również pod element <realm-name>, który zawiera nazwę realm (wartość ustawiana była w pliku jboss-service.xml). Element <security-role> przechowuje nazwę grupy, nasza mini aplikacja posiada dwie grupy, user - czyli zwykli użytkonicy, oraz admin - czyli administrator strony.

Możemy teraz przetestować to co stworzyliśmy. Uruchamiamy serwer JBoss i depoloy'ujemy na nim aplikację. Strona będzie dostępna pod adresem http://localhost:8080/JAASHelloWorld/ lub http://127.0.0.1:8080/JAASHelloWorld/.

Wylogowanie
Kiedy logowanie już działa, potrzebujemy jeszcze mechanizmu wylogowania. Jest na to bardzo szybki sposób. W katalogu WebContent/login tworzymy plik logout.jsp i umieszczamy w nim treść:
<%
session.invalidate();
response.sendRedirect("../index.jsp"); 
%>

Teraz gdy mamy już logowanie i wylogowywanie gotowe, struktura naszej aplikacji powinna wyglądać tak:


Tomcat 6, proste uwierzytelnianie - część 2

W pierwsze części artykułu mówiliśmy o tym jak prosto zabezpieczyć naszą aplikację przed niewłaściwymi osobami. Ale jak już zauważyliśmy ma ona jedną bardzo ważną wadę. Hasła które zapisywane są w bazie danych nie są szyfrowane. Czyli każdy kto ma wgląd do naszej bazy danych, ma dostęp do haseł i loginów użytkowników, co jest niedopuszczalne.
Dlatego omówimy teraz jak w szybki sposób szyfrować hasła w bazie danych bardzo popularnym algorytmem md5.
Cały artykuł jest oparty o aplikacje którą stworzyliśmy w pierwszej części artykułu.

Baza danych
Baza danych jest dokładnie taka sama jak w pierwszej części artykułu, czyli:

CREATE TABLE users (
 login VARCHAR(20),
 password VARCHAR(100)
);

CREATE TABLE user_roles (
 login VARCHAR(20),
 rolename VARCHAR(20)
);
Jedyne co wymaga zmiany to zaszyfrowanie hasła. Robimy to poprzez wywołanie polecenia INSERT, z tą różnica że hasło będzie zaszyfrowane. Aby zaszyfrować hasło użyłem przykładowej strony, która wyskoczył jako jedna z pierwszych w wyszukiwarce google.com, pod hasłem: md5 generator.
Tak wiec po zaszyfrowaniu haseł admin i user uzyskujemy wyniki:
  • admin = 21232f297a57a5a743894a0e4a801fc3
  • user = ee11cbb19052e40b07aac0ca060c23ee

INSERT INTO users VALUES('admin','21232f297a57a5a743894a0e4a801fc3');
INSERT INTO user_roles VALUES('admin','admin');
INSERT INTO users VALUES('user1','ee11cbb19052e40b07aac0ca060c23ee');
INSERT INTO user_roles VALUES('user1','user');

Pliki konfiguracyjne
Musimy jeszcze zmienić nasz plikach konfiguracyjny WebContent/META-INF/context.xml, w którym ustawialiśmy parametry konfiguracyjne bazy danych. Do elementu <Realm> dodajemy atrybut digest="nazwa_algorytmu_szyfrującego", w naszym wypadku będzie to MD5.
Plik po modyfukacji powinien wyglądać tak:

<?xml version="1.0" encoding="ISO-8859-1"?>
<Context antiResourceLocking="false" privileged="true">
<Realm className="org.apache.catalina.realm.JDBCRealm" debug="0"
 driverName="org.gjt.mm.mysql.Driver" connectionURL="jdbc:mysql://localhost/testdb"
 connectionName="root" connectionPassword="mysql" userTable="users"
 userNameCol="login" userCredCol="password" userRoleTable="user_roles"
 roleNameCol="rolename" digest="MD5"/>
</Context>
Po tych zmianach wystarczy ponownie zdeployować aplikacje na serwerze. Strona działa dokładnie tak samo jak wersja bez użycia algorytmu szyfrującego md5, ale jest o wiele bardzije bezpieczna.

środa, 17 lutego 2010

Tomcat 6, proste uwierzytelnianie - część 1

W tym prostym tutorialu przedstawię jak w bardzo prosty sposób zabezpieczyć zasoby naszej aplikacji działającej na bardzo popularnym serwerze aplikacji jakim jest Apache Tomcat 6.

Baza Danych
Na początek musimy przygotować strukturę bazy danych, gdzie będziemy trzymać nazwy użytkowników i przydzielone do nich nazwy ról. Skrypt który to zrobi wygląda tak:
CREATE TABLE users (
 login VARCHAR(20),
 password VARCHAR(100)
);

CREATE TABLE user_roles (
 login VARCHAR(20),
 rolename VARCHAR(20)
);
Pierwsza tabela users przechowuje nazwy użytkowników (login) i hasła (password) do ich kont. Druga tabela user_roles przechowuje nazwę użytkownika (login) i nazwę roli (rolename) do której użytkownika należy. Teraz wystarczy uzupełnić nasze tabele danymi:
INSERT INTO users VALUES('admin','admin');
INSERT INTO user_roles VALUES('admin','admin');
INSERT INTO users VALUES('user1','user');
INSERT INTO user_roles VALUES('user1','user');
Ja będę używał bazy MySQL, dlatego musimy jeszcze ściągnąć connector, który należy rozpakować i skopiować do katalogu tomcat_home/lib.

Aplikacja
Teraz możemy zająć się tworzeniem aplikacji. Ja używam Eclipse. Tworzymy Dynamic Web project, eclipse zadba o to aby stworzyć odpowiedni układ katalogów. U mnie wygląda to tak:



Kiedy mamy już szkielet naszej aplikacji, dodamy kilka stron, aby mieć na czym testować nasze uwierzytelnianie. Dodajemy do WebContent trzy katalogi: user, admin i login. Katalog admin będzie zawierał podstrony do których ma dostęp tylko administrator, natomiast katalog user będą mogli przeglądać tylko użytkownicy zalogowani. Katalog login będzie zawierał podstrony które będą potrzebne do zalogowania i wylogowania użytkownika z naszej aplikacji. Potrzebujemy także strony startowej, dlatego bezpośrednio w katalogu WebContent tworzymy strone index.jsp. Na razie zostawimy ją pustą, późnie wypełnimy ją jakąś treścią.

W katalogu login tworzymy trzy pliki:
  • login.jsp - zawiera formularz logowania
  • login_err.jsp - zawiera komunikat o nieudanej próbie logowania
  • logout.jsp - zawiera krótki kawałek kodu który odpowiada za wylogowanie użytkownika
Strona login/login.jsp zawiera prosty formularz dzięki któremu użytkownik będzie mógł się zalogować. Należy zwrócić tutaj uwagą na akcje jaką wykona formularz po kliknięciu przycisku, oraz na wartości atrybutu name w polach gdzie wprowadzamy login i hasło.
<html>
 <head>
  <title>Login</title>
 </head>
 
 <body>
  <form method="post" action="j_security_check">
   <div>
    Login:
    <input type="text" name="j_username" />
   </div>
   <div>
    Hasło:
    <input type="password" name="j_password"/>
   </div>
   <div>
    <input type="submit" value="LOGIN" />
   </div>
  </form>
 </body>
</html>

Strona login/login_err.jsp zawiera prosty komunikat o błędnym zalogowaniu:
<html>
 <head>
  <title>Login Error</title>
 </head>
 
 <body>
  <div>Logowanie się nie powiodło. Sprobuj jeszcze raz.</div>
 </body>
</html>
Strona login/logout.jsp wylogowywuje użytkownika i przekierowuje nas na stronę index.jsp.
<%
session.invalidate();
response.sendRedirect("../index.jsp"); 
%>

W katalogu user tworzymy plik user/index.jsp, plik będzie zawierał krótki komunika "Witaj użytkowniku" i dwa linki, jeden do strony głównej (index.jsp), drugi do strony login/logout.jsp.


<html>
 <head>
  <title>Uzytkonik</title>
 </head>
 
 <body>
  Witaj uzytkowniku
  <br />
  <a href="../index.jsp">cofnij</a>
  <br />
  <a href="../login/logout.jsp">logout</a>
 </body>
</html>
W katalogu admin tworzymy plik admin/index.jsp, który podobnie jak plik user/index.jsp będzie zawierał komunikat powitalny, tym razem jednak administratora systemu, oraz dwa linki.

<html>
 <head>
  <title>Administrator</title>
 </head>
 
 <body>
  Witaj administratorze
  <br />
  <a href="../index.jsp">cofnij</a>
  <br />
  <a href="../login/logout.jsp">logout</a>
 </body>
</html>
Wracamy teraz do naszej głównej strony index.jsp, dodamy do niej krótki komunikat powitalny oraz linki do naszych stron użytkownika (user/index.jsp) oraz administratora (user/index.jsp). Dodamy też możliwość wylogowania się, dostępną tylko dla zalogowanych użytkowników.
<html>
 <head>
  <title>Uzytkownik</title>
 </head>
 
 <body>
  Witaj na stronie testowej.
  <br />
  <a href="admin/index.jsp">Administrator</a>
  <br />
  <a href="user/index.jsp">Uzytkownik</a>
  <br />
  <%
  if(request.getUserPrincipal() != null){
  %>
  <a href="login/logout.jsp">logout</a>
  <%
  }
  %>
 </body>
</html>
Po stworzeniu wszystkich stron naszej małej aplikacji układ katalogów powinien wygląda tak:


Pliki konfiguracyjne, czyli to co najważniejsze
Teraz kiedy nasza mini aplikacja jest już gotowa, możemy zablokować dostęp do niektórych katalogów, w celu zabezpieczenia danych które są tam przechowywane przed niewłaściwymi osobami.
W katalogu WEB-INF znajduje się plik web.xml, w którym umieścimy informacje o tym, jakie podstrony naszej aplikacje będą niedostępne dla niezalogowanych użytkowników.
Plik web.xml po zmodyfikowaniu powinie wyglądać tak:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

 <display-name>HelloWorld</display-name>
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>

 <security-constraint>
  <web-resource-collection>
   <web-resource-name>AdminPages</web-resource-name>
   <description> accessible by authorised users </description>
   <url-pattern>/admin/*</url-pattern>
   <http-method>DELETE</http-method>
   <http-method>GET</http-method>
   <http-method>POST</http-method>
   <http-method>PUT</http-method>
  </web-resource-collection>
  <auth-constraint>
   <role-name>admin</role-name>
  </auth-constraint>
  <user-data-constraint>
   <transport-guarantee>NONE</transport-guarantee>
  </user-data-constraint>
 </security-constraint>

 <security-constraint>
  <web-resource-collection>
   <web-resource-name>UserPages</web-resource-name>
   <description> accessible by authorised users </description>
   <url-pattern>/user/*</url-pattern>
   <http-method>DELETE</http-method>
   <http-method>GET</http-method>
   <http-method>POST</http-method>
   <http-method>PUT</http-method>
  </web-resource-collection>
  <auth-constraint>
   <role-name>user</role-name>
   <role-name>admin</role-name>
  </auth-constraint>
  <user-data-constraint>
   <transport-guarantee>NONE</transport-guarantee>
  </user-data-constraint>
 </security-constraint>

 <login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
   <form-login-page>/login/login.jsp</form-login-page>
   <form-error-page>/login/login_err.jsp</form-error-page>
  </form-login-config>
 </login-config>

 <security-role>
  <role-name>admin</role-name>
 </security-role>
 <security-role>
  <role-name>user</role-name>
 </security-role>
</web-app>
To teraz krótki opis, co znajduje się w powyższym pliku.
Jak można zauważyć, w pliku wydzielone są trzy główne elementy: <security-constraint>, <login-config> i <security-role>. Element <security-constraint> zawiera informacje o blokowanych zasobach, oraz o tym jakie grupy użytkowników mają dostęp do informacje zawartych na tych stronach. Element <login-config> zawiera informacje o formularzu który ma się wyświetlić w razie odniesienia się do zablokowanych zasobów, w celu sprawdzenia czy użytkownik ma wystarczające prawa do oglądania treści zawartych na stronie. Element <security-role> przechowuje nazwę grupy, nasza mini aplikacja posiada dwie grupy, user - czyli zwykli użytkonicy, oraz admin - czyli administrator strony.

Nasza aplikacja do weryfikacji użytkownika wykorzystuje bazę danych, dlatego musimy stworzyć plik który będzie informował Tomcat'a o tym gdzie ma szukać informacji o loginach, hasłach i przynależności do grup. W tym celu w katalogu META-INF tworzymy plik context.xml.
<?xml version="1.0" encoding="ISO-8859-1"?>
<Context antiResourceLocking="false" privileged="true">
<Realm className="org.apache.catalina.realm.JDBCRealm" debug="0"
 driverName="org.gjt.mm.mysql.Driver" connectionURL="jdbc:mysql://localhost/testdb"
 connectionName="root" connectionPassword="mysql" userTable="users"
 userNameCol="login" userCredCol="password" userRoleTable="user_roles"
 roleNameCol="rolename" />
</Context>
Plik zawiera główny element <Realm> który posiada kilka ważnych atrybutów:
  • driverName - informacje o sterowniku z jakiego używamy
  • connectionURL - lokalizacja bazy danych, my używamy MySQl ktory działa pod adresem localhost/nazwa_bazy_danych
  • connectionName - nazwa użytkownika w bazie danych
  • connectionPassword - hasło do bazy danych
  • userTable - nazwa tabeli która przechowuje informacje o loginach i hasłach
  • userNameCol - nazwa kolumny która przechowuje login użytkownika
  • userCredCol - nazwa kolumny która przechowuje hasło użytkownika
  • userRoleTable - nazwa tabeli która przechowuje login i nazwą roli użytkownika
  • roleNameCol - nazwa kolumny która przechowuje nazwę roli
Teraz wystarczy stworzyć paczkę war z naszej aplikacji z zdeployować ją na serwerze Apache Tomcat, jeśli używamy eclipse wystarczy dodać serwer w zakładce Servers i uruchomić wraz z nasza aplikacją.

Nasza aplikacja co prawda działa, ale hasła które są przechowywane w bazie danych nie są szyfrowane. Dlatego w części 2 artykułu naprawimy ten błąd.