Section 13.9. A Database-Driven Authentication Servlet

   

13.9 A Database-Driven Authentication Servlet

In this section, we will write a complete authentication application. The application is usable almost right out of the box for incorporating into your own Java applications (or your CFMX applications for that matter). The only things you'd need to change are the database name and driver name in the utility class.

The application requires the following components :

  • An HTML page, which will simply contain a login form. The only interesting thing about this form is where the <form> tag's action attribute points. As mentioned above, we can define servlets to map to any arbitrary string extension we like. Because this book is called Java for ColdFusion Developers , we'll create a mapping in Tomcat's web.xml file to have any URL resource containing a .jfcf extension map to our servlet. So the HTML <form> tag action attribute looks like this: action="Login.jfcf" . Notice that no file named anything.jfcf actually exists. When the user submits the form, the mapping invokes the servlet to determine whether the username and password combination supplied is in the database.

  • An Access database called JavaForCF. This database contains a table called users . The users table has two columns : username and password . This is the database that stores our list of users allowed in the secure area. Of course, you do not need to use an Access database; if you use a different database, change the reference to the driver and change the database name.

  • A DBUtil class. This is a regular Java class. We have offloaded the database interaction (loading the driver, connecting, getting a result set, and disconnecting) to this utility class. This serves a couple of purposes. First, we can add methods to it and easily reuse the class. Second, it keeps our servlet clean and object oriented.

  • A Login servlet. This servlet will do three things. First, it instantiates a DBUtil object to hit the database. Second, it uses the result to determine if the user should be authenticated. If the user is in the database, the servlet forwards the request onto the secure.jsp page. If the user is not in the database, the servlet redirects the user to the login screen. Third, if the user is good, then the username is placed into the session object. This will be tested on the secure.jsp page.

  • Secure.jsp . This is the page that we want to keep secure. This page simply tests to see whether the user is in the session object. If this value is present, then the user authenticated correctly and is shown the menu. If this value is null , then the user tried to bypass the servlet, has not authenticated, and is told to go login.

Now that we know what we need in this application, let's look at the code listings.

13.9.1 web.xml

 <?xml version="1.0" encoding="ISO-8859-1"?>  <!DOCTYPE web-app     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"     "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <servlet> <servlet-name>Login</servlet-name> <servlet-class>com.javaforcf.utils.Login</servlet-class> </servlet>         <servlet-mapping>             <servlet-name>Login</servlet-name>             <url-pattern>*.jfcf</url-pattern>         </servlet-mapping> </web-app> 

The web.xml file was not mentioned in the list of resources above, because it is not application-specific. We do need to modify the file as shown in this listing, however, to create the mapping.

13.9.2 Login.html

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  <HTML>   <HEAD>     <TITLE></TITLE>   </HEAD>   <BODY onLoad="document.loginform.username.focus()">   <h2 align="center">Please login</h2>   <p align="center">     <form action="auth.jfcf" method="POST" name="loginform">     username: <input type="text" name="username">     <br>     password: <input type="password" name="password">     <br>     <input type="submit" value="login">   </p>     </form>   </BODY> </HTML> 

Notice the action attribute of the <form> tag. There is no file on my server called auth with a .jfcf extension (or any other extension for that matter). The web.xm l file invokes the mapped servlet, which is called Login , any time a request is made for a file ending in .jfcf .

Note

Remember that servlets are just regular Java classes that extend Http-Servlet and override its doGet() and doPost() methods. So, you don't reference them with any file name extension.


Figure 13.3. The initial login screen.

graphics/13fig03.gif

13.9.3 DBUtils.java

[View full width]
 
[View full width]
/* File: DBUtils. * Purpose: Utility class to let us reuse database * connection code. */ package com.javaforcf.utils; import java.sql.*; import java.util.*; public class DBUtils { Connection con; //************authenticateUser() public boolean authenticateUser(String username, String password) { ResultSet rs = null; boolean isAuthenticated = false; try { connect(); PreparedStatement authenticateUser; String s = new String("SELECT username, password FROM users WHERE username graphics/ccc.gif = ?" + " AND password = ?"); authenticateUser = con.prepareStatement(s); authenticateUser.setString(1, username); authenticateUser.setString(2, password); rs = authenticateUser.executeQuery(); while (rs.next()) { isAuthenticated = true; } disconnect(); } catch (ClassNotFoundException cnfe) { System.err.println(cnfe.getMessage()); } catch (SQLException sqle) { sqle.printStackTrace(); } catch (Exception e) { System.err.println(e.getMessage()); } return isAuthenticated; } // end authenticateUser // ************ CONNECT public void connect() throws ClassNotFoundException, SQLException, Exception { try { // load driver Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // make connection to Access database con = DriverManager.getConnection("jdbc:odbc:javaforcf"); } catch (ClassNotFoundException cnfe) { System.err.println(cnfe.getMessage()); } catch (SQLException sqle) { sqle.printStackTrace(); } catch (Exception e) { System.err.println(e.getMessage()); } } //end connect //********* DISCONNECT public void disconnect() throws SQLException { try { if ( con != null ) { //close connection con.close(); } } catch (SQLException sqle) { sqle.printStackTrace(); } } // end disconnect() } // eof

This file defines the code to authenticate the user in the database. If you want to use a different database, you can define that here. You might consider expanding the flexibility of this class by overloading the method to accept a database connect string and driver name as parameters. By offloading this aspect of the work to a utility class, we can maximize the ease of reuse and flexibility of this application; perhaps you don't want to even use a database for authentication. As alternatives, you could define a method to read in an XML file, traverse its elements, and determine authentication that way, or you could use LDAP.

13.9.4 Login.java

 /* File: Login.java   * Purpose: Servlet to perform login authentication  *  with a username and password passed in from a form.  *  This hits an Access database and checks if it has a record,  *  if so, sets the username into the session object.  */     // package this one up package com.javaforcf.utils; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class Login extends HttpServlet {     public void doGet(HttpServletRequest request,                         HttpServletResponse response)                 throws ServletException, IOException {         // if this is an HTTP GET request, forward         // it in effect to doPost(). They will just         // do the same thing         doPost(request, response);     }     public void doPost(HttpServletRequest request,                        HttpServletResponse response)                 throws ServletException, IOException {                 // access the session object, create                 // a session if it doesn't exist         HttpSession session = request.getSession(true);         String username = request.getParameter("username");         String password = request.getParameter("password");             // create a variable to hold where we should             // redirect the user             // This will be checked twice--             // first if the user didn't fill out the form, and             // again if the username/password combination             // specified does not have a match in the database.             // It will be set to a different value depending on             // the validity of the login         String redirect;             // do database lookup         DBUtils db = new DBUtils();         boolean isAuth = db.authenticateUser(username, password);             // login good, add user to session and redirect to             // secure page         if (isAuth) {            session.setAttribute("USER", username);            redirect = "/secure.jsp";         }             // bad login         else {             redirect = "/login.html";         }             // go to either the secure page or form page         ServletContext context = getServletContext();         RequestDispatcher dispatcher =            context.getRequestDispatcher(redirect);            dispatcher.forward(request, response);     } } // eof 

This is our servlet that invoked the DBUtil.java class and passes the request parameters from the form into our authenticateUser() method. If the method returns true , the servlet forwards to the secure.jsp page. We will cover JSPs in full in the next chapter.

13.9.5 secure.jsp

 <%--File: secure.jsp      Purpose: show menu to authenticated user, demonstrate     interaction with servlet, introduce basic JSP concepts. --%> <%@page contentType="text/html"%> <html> <head>     <title>Some secure page</title> </head> <body> <%     String thisUser = (String) session.getAttribute("USER");     if (thisUser != null) { %> <h1>Welcome, <%= thisUser %></h1> <br> Here are your secret things: <ul>     <li>one</li>     <li>two</li>     <li>three</li> </ul> <%-- user did not authenticate. --%> <% // close the if statement brace     }     else { %> <h2>You must be logged in to access this page</h2> <a href="login.html">Go to login</a> <%-- close the else brace--%> <%     } %> </body> </html> 

There is a lot to talk about in this JSP. Since we have not formally introduced JSPs yet, we'll just give it an overview. The neat thing about this JSP at this point is that it introduces a number of the important elements of JSPs. Here are the main things that stand out about this page:

  • The comments. <%-- I am a JSP comment --%> This style of comment works exactly like a ColdFusion comment <!--- something ---> . It is not visible to the browser, but it is returned as whitespace in the HTML source.

  • The directive starts with <%@... , and the JSP directive tells the client what to expect about this response. In this example, it sets the MIME type for the current page scope to text/html .

  • The scriptlet is the section of the JSP that is enclosed within <% ... %>. Scriptlets allow you to write Java programming language code directly on the JSP. So the String thisUser... statement and the if statement are standard Java code that declare and initialize a new string and test its value, just like you would in a Java class. Notice that we can also use Java-style comments ( // ) within these blocks as well.

We will cover JSPs formally in the next chapter.

Note

See the HttpServlet API reference in the appendix of this book for more information on the methods and exceptions available to you when writing servlets. Because things such as sessions and HTTP requests are very familiar to the ColdFusion developer, we do not discuss them in depth here, but the API should get you going.


Figures 13.4 and 13.5 show the results of an unsuccessful and a successful login, respectively.

Figure 13.4. Attempting to bypass the login.

graphics/13fig04.gif

Figure 13.5. Login successful.

graphics/13fig05.gif


   
Top


Java for ColdFusion Developers
Java for ColdFusion Developers
ISBN: 0130461806
EAN: 2147483647
Year: 2005
Pages: 206
Authors: Eben Hewitt

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net