670 likes | 818 Views
Fejlett Programoz ási Technikák 2. 15 / 9. Az előző mai előadás tartalma:. Számítógépes biztonság Jáva és a biztonság Biztonsági architektúra Titkosító architektúra JCE JAAS JSSE GSSE. Források. http://java.sun.com/products/servlet/docs.html
E N D
Az előző mai előadás tartalma: • Számítógépes biztonság • Jáva és a biztonság • Biztonsági architektúra • Titkosító architektúra • JCE • JAAS • JSSE • GSSE
Források • http://java.sun.com/products/servlet/docs.html • http://java.sun.com/developer/onlineTraining/Servlets/Fundamentals/contents.html • http://www.onjava.com/pub/a/onjava/2002/07/31/tomcat.html
A mai előadás tartalma • Java Servlet • Servlet Interfész • Servlet Context • Request • Response • Filter • Session • Web Application
Webes szolgáltatások • Java Servlet • Környezet • Tomcat 4.0 • server.xml • web.xml
Webes szolgáltatások • Java WSDP fejlesztői csomag • JSP • Java Servlet • Java XML pack • Tomcat • Ant • Tomcat + J2SDK
Java Servlet • Java technológiára épülő web komponens • platform független, bytecode • dinamikusan betölthető • dinamikus tartalom előállítására alkalmas • egy tároló menedzseli (servlet engine) • a web szerver vagy az alkalmazásszerver része, vagy önálló alkalmazás saját web szerverrel (Tomcat) • biztosítja azt a környezetet amelyen keresztül a kérések és a válaszok (request, response) lekezelhetőek • tartalmazza és menedzseli a servlet-eket egész életfolyamatuk alatt
Példa • A kliens kapcsolatba lép a web szerverrel és elküld egy HTTP kérést • A kérést a web szerver átadja a servlet tárolónak amely futhat • ugyanabban a process-ben • ugyanazon a gépen másik process-ben • másik gépen • A servlet tároló a kérés paraméterei alapján meghívja a megfelelő servlet-et (URL) • A servlet a kérés paraméterei alapján megállapítja mit szeretne a kliens ennek megfelelően végrehajtja a megfelelő műveleteket. Válaszol a kliensnek a válasz objektum segítségével • Miután a servlet tároló megállapította, hogy a servlet befejezte a feladatot átadja a vezérlést a web szervernek
A servlet-ek előnyei • hatékony • hagyományos CGI: n hívás n process • kényelmes • hatékony eszköztár a HTML űrlap adatok értelmezésére (http fejléc, süti, viszony) • platform független • biztonságos • nem általános shell program környezetben fut (itt ki kell szűrni a speciális karaktereket …) • buffer túlcsordulás nem léphet fel • JVM (hibakezelés, …) • olcsó • Tomcat - ingyenes
A servlet interfész • a servlet interfész megvalósítása vagy öröklése teszi a servlet-et servlet-té (javax.servlet.Servlet) • GenericServlet absztrakt osztály • service • HttpServlet absztrakt osztály • HttpServletRequest • HttpServletResponse • kérés kezelő metódusok: • service • minden kérésnél meghívódik • HTTP specifikus kérés kezelő metódusok: • doGet • doPost • doPut • doDelete • doHead • doOptions • doTrace • getLastModified leggyakrabban használtak
Példa import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloWWW extends HttpServlet { public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String docType = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"; out.println(docType +"<HTML>\n<HEAD><TITLE>Hello</TITLE></HEAD>\n" + "<BODY>\n<H1>Hello WWW</H1>\n</BODY></HTML>"); } }
Servlet-ek csomagolása • többen is fejleszthetnek egy web portált • egy könyvtár használata nem célszerű • külön könyvtárat célszerű használni • csomagok használata (package) • csomagnév.servlet
A servlet életciklusa • betöltés, példányosítás • a tároló indításakor • amikor szükség van az adott servlet-re • inicializálás – csak a betöltéskor • init metódus • argumentum nélküli – nem olvas semmilyen beállítást • ServletConfig object – az első sorban kötelező meghívnia super.init(config) metódust • betöltéskor pl.: JDBC kapcsolat felépítése • kérés feldolgozás – minden egyes kérésre új szál • service • meghívja a megfelelő doXXX metódust (Request, Response) • nem célszerű ezt felülírni (használjuk a megfelelő doXXX metódusokat) • doXXX • a szolgáltatás befejezése – régóta nem aktív, server leálítása,… • destroy – adatbázis kapcsolat bezárása, háttérszálak leállítása, …
1. rész import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ShowMessage extends HttpServlet { private String message; private String defaultMessage = "No message."; private int repeats = 1; public void init(ServletConfig config) throws ServletException { super.init(config); message = config.getInitParameter("message"); if (message == null) { message = defaultMessage; } try { String repeatString = config.getInitParameter("repeats"); repeats = Integer.parseInt(repeatString); } catch(NumberFormatException nfe) {} }
public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String title = "The ShowMessage Servlet"; out.println(ServletUtilities.headWithTitle(title) + "<BODY BGCOLOR=\"#FDF5E6\">\n" + "<H1 ALIGN=CENTER>" + title + "</H1>"); for(int i=0; i<repeats; i++) { out.println(message + "<BR>"); } out.println("</BODY></HTML>"); } } 2. rész
Egy-szál modell • alap esetben a servlet egy példánya található meg a memóriában • minden egyes kérés teljesítésére egy új szál indul • figyelnünk kell a párhuzamos futásra, a megfelelő erőforrások zárolására • Request, Response objektum csak a servlet futása közben használható ! (recycling) • megakadályozható a párhuzamos futtatás a SingleThreadModel interfész megvalósításával • ekkor egyszerre csak egy szál fut (a kérések egy várakozási sorban figyelnek ) • ezzel a megoldással nagyon lelassíthatjuk rendszerünk működését !
Servlet futási környezet • ServletContext interfész • ilyennek látja a servlet a környezetét • a tárolónak kell megvalósítania az interfészt • ServletConfig config = getServletConfig(); • a ServletContext objektum segítségével a servlet • eseményeket menthet el (log) • megállapíthatja az egyes források URL címét • elmenthet és kiolvashat olyan értékeket a környezetben melyet más, a környezetben futó servlet-ek olvashatnak
Hasznos metódusok • inicializáló paraméterek: • getInitParameter • getInitParameterNames • környezeti paraméterek (JavaBean-ek használata): • setAttribute • getAttribute • getAttributeNames • removeAttribute • erőforrások (HTML, GIF,JPEG) (nem alkalmasak dinamikus tartalom kezelésére pl.: index.jsp): • getResource • getResourceAsStream • ideiglenes könyvtár: • File tempdir=(File)getServletContext().getAttribute("javax.servlet.context.tempdir");
Kérés objektum • HttpServletRequest • Minden információ a HTTP kérésből • POST paraméterek • getParameter • getParameterNames • getParameterValues • getParameterMap • HTTP fejléc
A HTML űrlap által küldött adatok kezelése • GET metódus esetén az URL-ben kódolva jelennek meg az adatok: • http://host/path?user=Marty+Hall&origin=bwi&dest=lax • POST metódus esetén a fejlécben vagy a törzsben helyezkednek el • getParameter metódussal a POST kezelhető ! • karakterlánc (string) a visszatérési érték • üres karakterlánc, ha nincs értéke a paraméternek • NULL, ha nincs ilyen paraméter • getParameterValues – egy karaterlánc tömböt ad vissza (ekkor egy paraméternek több értéke lehet pl.: checkbox) • a paraméter nevek érzékenyek a kis és a nagy betűre • getParameterNames - a használható paraméterek listáját adja vissza (Enumeration)
Perl script példa read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $FORM{$name} = $value; }
Példa: (HTML) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <TITLE>Collecting Three Parameters</TITLE> </HEAD> <BODY BGCOLOR="#FDF5E6"> <H1 ALIGN="CENTER">Collecting Three Parameters</H1> <FORM ACTION="servlet/ThreeParams” METHOD=”POST”> First Parameter: <INPUT TYPE="TEXT" NAME="param1"><BR> Second Parameter: <INPUT TYPE="TEXT" NAME="param2"><BR> Third Parameter: <INPUT TYPE="TEXT" NAME="param3"><BR> <CENTER> <INPUT TYPE="SUBMIT"> </CENTER> </FORM> </BODY> </HTML>
Példa (Servlet) import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ThreeParams extends HttpServlet { public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String title = "Reading Three Request Parameters"; out.println(ServletUtilities.headWithTitle(title) +"<BODY BGCOLOR=\"#FDF5E6\">\n<H1 ALIGN=CENTER>" + title + "</H1>\n<UL>\n <LI><B>param1</B>: "+ request.getParameter("param1") + "\n" + " <LI><B>param2</B>: "+ request.getParameter("param2") + "\n" + " <LI><B>param3</B>: "+ request.getParameter("param3") + "\n" +"</UL>\n" + "</BODY></HTML>");} public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
A HTTP paraméterek kezelése • getHeader(”paraméter”) • string – ha volt ilyen paramtér • NULL – ha nem volt ilyen paraméter • ezzel elvileg minden típus olvasható azonban vannak az egyes speciális paraméterekre külön metódusok: • getCookies – egy cookie tömböt kapunk • getAuthType, getRemoteUser • getContentLength • getContentType • getDateHeader ,getIntHeader • getHeaderNames – minden fejléc név egy Enumeration objektumban • getHeaders – ha egy fejléc többször is szerepel akkor is visszaadja a fenti módon • getMethod • getRequestURI • getProtocol
Minden paraméter kiíratása Minden fejléc kiíratása import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import java.util.*; public class ShowRequestHeaders extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String title = "Servlet Example: Showing Request Headers"; out.println( … Enumeration headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()) { String headerName = (String)headerNames.nextElement(); out.println("<TR><TD>" + headerName); out.println(" <TD>" + request.getHeader(headerName)); } out.println("</TABLE>\n</BODY></HTML>"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response);} }
Válasz objektum • magában foglal minden információt a kliens számára • használhatunk buffer-t • getBufferSize • setBufferSize (a tároló nagyobbra is állíthatja) • isCommitted • reset • resetBuffer – a fejrészt és a státusz kódot nem törli • flushBuffer • Fejlécek • setHeader • addHeader • setIntHeader • setDateHeader • addIntHeader • addDateHeader • Használjuk a: X-Powered-By fejlécet (X-Powered-By: Servlet/2.4 JSP/2.0 (Tomcat/5.0 JRE/1.4.1)) • Átirányítás • sendRedirect • sendError
Státusz kezelése • response.setStatus(int), • public void sendError(int code, String message) • public void sendRedirect(String url) • response.sendRedirect(response.encodeURL(url))
Képek létrehozása • Kép létrehozása: Frame f = new Frame(); f.addNotify(); // nem kell az ablakot megnyitni csak egy ilyen objektumot hozunk létre Image img = f.createImage(width, height);, • Rajzoljunk a képbe: Graphics g = img.getGraphics(); g.fillRect(...); g.drawString(...); • A Content-Type válasz fejléc beállítása response.setContentType("image/gif"); • Egy válasz stream-et nyitunk OutputStream out = response.getOutputStream(); • Küldjük el képünket GIF formátumban, itt egy kódolót kell használnunk. Ilyent a http://www.acme.com/java/ címen tudunk elérni. try {new GifEncoder(img, out).encode();} catch(IOException ioe) {}
Weboldalak tömörítése Tömörített oldal … import java.util.zip.*; public class EncodedPage extends HttpServlet { public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); String encodings = request.getHeader("Accept-Encoding"); String encodeFlag = request.getParameter("encoding"); PrintWriter out; String title; if ((encodings != null) && (encodings.indexOf("gzip") != -1) && !"none".equals(encodeFlag)) { title = "Page Encoded with GZip"; OutputStream out1 = response.getOutputStream(); out = new PrintWriter(new GZIPOutputStream(out1), false); response.setHeader("Content-Encoding", "gzip"); } else { title = "Unencoded Page"; out = response.getWriter(); } out.println( "<head></head><BODY BGCOLOR=\"#FDF5E6\">\n" + "<H1 ALIGN=CENTER>" + title + "</H1>\n"); String line = "Blah, blah, blah, blah, blah. " + "Yadda, yadda, yadda, yadda."; for(int i=0; i<10000; i++) { out.println(line); } out.println("</BODY></HTML>"); out.close();}}
Viszony követés • a HTTP állapotmentes • fontos az állapotkövetés: • bevásárló kosár … • négy megoldás: • sütik • URL átírás • HTTPS viszony követés • rejtett HTML mezők
Sütik (Cookies) • rövid szöveges információk melyeket a web szerver küld a kliensnek • segítségével • azonosíthatjuk a felhasználót egy e-commerce viszony alatt (bevásárló kosár) • elkerülhető a felhasználói név és a jelszó (alacsony biztonsági szint) • személyre szabható az oldal • a felhasználói információ értékes (célozott reklámok)
Problémák • 4 kbyte, 20 cookie/site, 300 süti összesen • az emberek nem szeretik, ha a kereső gépek megjegyzik mit szeretnek keresni • a sütikben tárolt információ nem biztonságos (más is használhatja a gépet, lemásolható a süti) • a fenti okok miatt a felhasználók gyakran kikapcsolják a sütiket
Sütik használata • new Cookie(name, value) • cookie.setXxx • response.addCookie(cookie) • request.getCookies – egy tömböt ad vissza melynek Cookie objektum elemei vannak, NULL ha nincs süti • cookie.getXxx
Sütik létrehozása • sem a neve sem az értéke nem tartalmazhatja a következő karaktereket: [ ] ( ) = , " / ? @ : ; • a következő metódusoknak meg van a getXxx párja is • setComment() – megjegyzést adhatunk a sütihez • setDomain() – segítségével beállíthatjuk a sütihez tartozó tartományt (a böngésző többek között ez alapján állapítja meg kinek mit adhat vissza) • setMaxAge() – a süti érvényességének időtartamát állíthatjuk be másodpercben (-1 csak a jelenlegi viszonyban érvényes) • setName() – a süti nevét állítja be • setPath() – a tartományon belüli érvényességet adja meg • setSecure() – csak titkosított kapcsolaton keresztül vihető át • setValue() – az értékét adhatjuk meg
Sütik létrehozása import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class SetCookies extends HttpServlet { public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { for(int i=0; i<3; i++) { Cookie cookie = new Cookie("Session-Cookie " + i,"Cookie-Value-S" + i); response.addCookie(cookie); cookie = new Cookie("Persistent-Cookie " + i,"Cookie-Value-P" + i); cookie.setMaxAge(3600); response.addCookie(cookie); } response.setContentType("text/html"); PrintWriter out = response.getWriter(); String title = "Setting Cookies"; out.println (”<head></head><BODY BGCOLOR=\"#FDF5E6\">\n" + "<H1 ALIGN=\"CENTER\">" + title + "</H1>\n" + "</BODY></HTML>"); } }
Sütik kiolvasása import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ShowCookies extends HttpServlet { public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String title = "Active Cookies"; out.println(ServletUtilities.headWithTitle(title) + … Cookie[] cookies = request.getCookies(); Cookie cookie; for(int i=0; i<cookies.length; i++) { cookie = cookies[i]; out.println("<TR>\n" + " <TD>" + cookie.getName() + "\n" + " <TD>" + cookie.getValue()); } out.println("</TABLE></BODY></HTML>"); } }
URL átírás • http://host/path/file.html;jsessionid=1234, • nem tiltható le
HTML rejtett mező • <INPUT TYPE="HIDDEN" NAME="session" VALUE="..."> • csak akkor működik ha minden oldal dinamikusan generált
Egy teljesebb megoldás • HttpSession API • magas szintű interfész mely sütiken vagy URL átíráson alapul • sütit használ ha lehetséges, amennyiben nem akkor átvált URL átírásra • az alsó részeivel nem kell foglalkoznunk
Létrehozása • HttpSession session = request.getSession(true); • létrehoz egy viszony objektumot • amennyiben már volt egy (valamikor régen, vagy most) akkor azt nyitja meg (true) • a HttpSession objektum a szerveren tárolódik • komoly adatstruktúrával rendelkezhet melyet mi adhatunk meg
Példa: HttpSession session = request.getSession(true); ShoppingCart cart = (ShoppingCart)session.getValue("shoppingCart"); if (cart == null) { cart = new ShoppingCart(); session.putValue("shoppingCart", cart); } doSomethingWith(cart);
Metódusok • set/getAttribute() • removeAttribute() • getAttributeNames() – enumeration • getId() – a viszony azonosítót adja vissza • isNew() – true ha a kilens még nem látta a viszonyt • getCreationTime() • getLastAccessedTime() • getMaxInactiveInterval() • invalidate()
A kérés továbbadása • RequestDispatcher interfész • a ServletContext objektumból tudjuk előállítani: • getRequestDispatcher – a servlet elérési útvonalát adhatjuk meg (a futási környezeten belül /-el kezdődik) • getNamedDispatcher – a servlet ServletContext-ben ismert nevét adhatjuk meg • továbbítás: • include – nem módosíthatja a válsz objektum fejléc mezőit, • forward – csak akkor használhatjuk, ha még nem válaszoltunk a kliensnek (nincs adat a bufferben, ezt előbb törölni kell) • az esetleges paraméterek elsőbbséget élveznek
Példa String path = “/raisons.jsp?orderno=5”; RequestDispatcher rd = context.getRequestDispatcher(path); rd.include(request, response);
Tomcat könyvtár hierarchia • bin -> itt helyezkednek el az indító, leállító szkriptek fájlok • log -> log fájlok • lib -> jar fájlok • conf -> server.xml • itt tudunk új környezetet létrehozni • webapps -> webes alkalmazások könyvtára
server.xml • server elem – egy lehet belőle • service elem – egy vagy több connector elem lehet benne de egy engine elem • connector – HTTP1.1 vagy Warp itt tudjuk például a port-ot beállítani • engine – a Tomcat szolgáltatási pontja, ezen belül tudjuk létrehozni például a virtuális címeket • host – itt tudjuk megadni a hozzá tartozó URL-t és a gyökér könyvtárat • contex – az egyes alkalmazások környezetéet definiálja a host-on belül.
Példa <Server port="8005" shutdown="SHUTDOWN" debug="0"> <Service name="Tomcat-Standalone"> <Connector className="org.apache.catalina.connector.http.HttpConnector" port="8080" minProcessors="5" maxProcessors="75" enableLookups="true" redirectPort="8443" acceptCount="10" debug="0" connectionTimeout="60000"/> <Engine name="Standalone" defaultHost="localhost" debug="0"> <Logger className="org.apache.catalina.logger.FileLogger" prefix="catalina_log." suffix=".txt" timestamp="true"/> <Realm className="org.apache.catalina.realm.MemoryRealm" /> <Host name="localhost" debug="0" appBase="webapps" unpackWARs="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="common"/> <Logger className="org.apache.catalina.logger.FileLogger" directory="logs" prefix="localhost_log." suffix=".txt" timestamp="true"/> <Context path="/teszt" docBase="teszt" debug="0" privileged="true"> <Logger className="org.apache.catalina.logger.FileLogger" prefix="localhost_examples_log." suffix=".txt" timestamp="true"/> </Context> </Host> </Engine> </Service> </Server>
Alkalmazás környezet • html, jsp, … • WEB-INF • classes – itt helyezkednek el a class fájlaink (jó esetben csomagokban)com.mycompany.mypackage.MyServlet /WEB-INF/classes/com/mycompany/mypackage/MyServlet.class • web.xml – leírja az általunk használt servlet-eket, …, újra kell indítani a Tomcat-et, hogy újra értelmezze • lib – az általunk használt jar fájlokat helyezhetjük el itt pl.: jdbc fájlok