Logging User Access with Filters


One of the primary uses of filters in Ajax applications is to log user accesses, something that’s particularly important if security is an issue. Here’s an example, log.html, which accesses log.jsp on the server:

 <html>   <head>     <title>Using a filter for user logging</title>     <script language = "javascript">       var XMLHttpRequestObject = false;       if (window.XMLHttpRequest) {         XMLHttpRequestObject = new XMLHttpRequest();       } else if (window.ActiveXObject) {         XMLHttpRequestObject = new           ActiveXObject("Microsoft.XMLHTTP");       }       function getData(dataSource, divID)       {         if(XMLHttpRequestObject) {           var obj = document.getElementById(divID);           XMLHttpRequestObject.open("GET", dataSource);           XMLHttpRequestObject.onreadystatechange = function()           {             if (XMLHttpRequestObject.readyState == 4 &&               XMLHttpRequestObject.status == 200) {                 obj.innerHTML =                   XMLHttpRequestObject.responseText;             }           }           XMLHttpRequestObject.send(null);         }       }     </script>   </head>   <body>     <H1>Using a filter for user logging</H1>     <form>       <input type = "button" value = "Get the message"         onclick = "getData('log.jsp', 'targetDiv')">     </form>     <div >       <p>The fetched message will appear here.</p>     </div>   </body> </html> 

Here’s what the accessed JSP, log.jsp looks like:

 <html>     <head>         <title>Logging user access</title>     </head>     <body>         <h1>Logging user access</h1>         You have been logged.         <br>     </body> </html>

The trick here is to use a filter, called LogFilter in this case, to log the user access. Here’s how you connect LogFilter to log.jsp in 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/j2ee/dtds/web-app_2_3.dtd"> <web-app>   <filter>     <filter-name>Log Filter</filter-name>     <filter-class>LogFilter</filter-class>   </filter>   <filter>     <filter-name>Authentication</filter-name>     <filter-class>PasswordFilter</filter-class>   </filter>   <filter-mapping>     <filter-name>Log Filter</filter-name>     <url-pattern>/log.jsp</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>Authentication</filter-name>     <url-pattern>/password.jsp</url-pattern>   </filter-mapping> </web-app>

Now it’s time to write the filter in Java, LogFilter.java. That filter starts as you’d expect:

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public final class LogFilter implements Filter {     .     .     . }

As you know, you have to support three methods in a filter: doFilter, init, and destroy:

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public final class LogFilter implements Filter  {   public void doFilter(ServletRequest request, ServletResponse      response,     FilterChain chain)     throws IOException, ServletException    {         .         .         .   }         .         .         .   public void destroy() { }   public void init(FilterConfig filterConfig) {         .         .         .   } }

This filter differs from PasswordFilter in that it’s going to need the FilterConfig object passed to the init method in order to write to a log file. That means you should save the FilterConfig object this way to make it accessible in the doFilter method-the Java this keyword points to the current object, so this.filterConfig refers to the filterConfig variable stored in the filter; the filterConfig variable is also declared private, which makes it inaccessible outside the current filter object:

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public final class LogFilter implements Filter  {   private FilterConfig filterConfig = null;   public void doFilter(ServletRequest request, ServletResponse      response,     FilterChain chain)     throws IOException, ServletException    {         .         .         .   }         .         .         .   public void destroy() { }   public void init(FilterConfig filterConfig)    {     this.filterConfig = filterConfig;   } } import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public final class LogFilter implements Filter  {   private FilterConfig filterConfig = null;   public void doFilter(ServletRequest request, ServletResponse      response,     FilterChain chain)     throws IOException, ServletException    {     long start = System.currentTimeMillis();         .         .         .   }   public void destroy() { }   public void init(FilterConfig filterConfig)    {     this.filterConfig = filterConfig;   } }

This filter logs users’ IP addresses (you can log users’ usernames as well, as described in Chapter 15, but that means your users must be logged in first), the resource they’re accessing (such as a JSP page), and the amount of time they spend with the resource. To track the amount of time, begin by getting the current system time, in milliseconds, before transferring control to the resource users want to look at:

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public final class LogFilter implements Filter  {   private FilterConfig filterConfig = null;   public void doFilter(ServletRequest request, ServletResponse      response,     FilterChain chain)     throws IOException, ServletException    {     long start = System.currentTimeMillis();         .         .         .   }   public void destroy() { }   public void init(FilterConfig filterConfig)    {     this.filterConfig = filterConfig;   } }

Next, you can get the user’s IP address with the request object’s getRemoteAddr method this way:

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public final class LogFilter implements Filter {   private FilterConfig filterConfig = null;   public void doFilter(ServletRequest request, ServletResponse     response,     FilterChain chain)     throws IOException, ServletException   {     long start = System.currentTimeMillis();     String address =  request.getRemoteAddr();         .         .         .   }   public void destroy() { }   public void init(FilterConfig filterConfig)   {     this.filterConfig = filterConfig;   } }

You can also get the URL of the Web resource (JSP page, servlet, HTML page, and so on) that the user is trying to access using the request object’s getRequestURI method:

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public final class LogFilter implements Filter {   private FilterConfig filterConfig = null;   public void doFilter(ServletRequest request, ServletResponse     response,     FilterChain chain)     throws IOException, ServletException   {     long start = System.currentTimeMillis();     String address =  request.getRemoteAddr();     String file = request.getRequestURI();         .         .         .   }   public void destroy() { }   public void init(FilterConfig filterConfig)   {     this.filterConfig = filterConfig;   } }

Note 

URI stands for universal resource indicator, which in practice currently means a URL, or universal resource locator.

However, the code is not going to work as written because as things stand, the request object is an object of the Java ServletRequest class, as you can see in the declaration of the doFilter method:

 public void doFilter(ServletRequest request, ServletResponse   response,   FilterChain chain)   throws IOException, ServletException {       .       .       . }

The ServletRequest class does not support the getRequestURI method, so you have to change the code here to avoid a compiler error. In fact, because our filter is online, the request object passed to the doFilter method is of a class based on the ServletRequest class, the HttpServletRequest class, and the HttpServletRequest class does support the getRequestURI method. So you can tell Java that you’re really dealing with an HttpServletRequest object this way:

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public final class LogFilter implements Filter {   private FilterConfig filterConfig = null;   public void doFilter(ServletRequest request, ServletResponse     response,     FilterChain chain)     throws IOException, ServletException   {     long start = System.currentTimeMillis();     String address =  request.getRemoteAddr();     String file = ((HttpServletRequest) request).getRequestURI();         .         .         .   }   public void destroy() { }   public void init(FilterConfig filterConfig)   {     this.filterConfig = filterConfig;   } }

Now you have the user’s IP address and requested URL, as well as the start time of his or her Web resource access. Now it’s time to pass control on to that Web resource with chain.doFilter:

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public final class LogFilter implements Filter  {   private FilterConfig filterConfig = null;   public void doFilter(ServletRequest request, ServletResponse      response,     FilterChain chain)     throws IOException, ServletException    {     long start = System.currentTimeMillis();     String address =  request.getRemoteAddr();     String file = ((HttpServletRequest) request).getRequestURI();     chain.doFilter(request, response);         .         .         .     );   }   public void destroy() { }   public void init(FilterConfig filterConfig)    {     this.filterConfig = filterConfig;   } }

That calls the Web resource the user was trying to access, and after that resource does its thing, control returns to you in the filter, where you can write to the log. To do that, you can use the FilterConfig object’s getServletContext method to get the current servlet context (the servlet context of a Web application lets you store data and share that data between servlets and between JSPs, among other things). The servlet context object has a method that lets you write to a log file, the log method, and you can use that method like this:

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public final class LogFilter implements Filter  {   private FilterConfig filterConfig = null;   public void doFilter(ServletRequest request, ServletResponse      response,     FilterChain chain)     throws IOException, ServletException    {     long start = System.currentTimeMillis();     String address =  request.getRemoteAddr();     String file = ((HttpServletRequest) request).getRequestURI();     chain.doFilter(request, response);     filterConfig.getServletContext().log(         .         .         .     );   }   public void destroy() { }   public void init(FilterConfig filterConfig)    {     this.filterConfig = filterConfig;   } }

To write to the log method, you pass it a string. In this case, that string contains the URL the user was accessing, the user’s IP address, and the time he or she took on the Web resource, which you can get by subtracting the starting time from the current time, like this:

 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public final class LogFilter implements Filter  {   private FilterConfig filterConfig = null;   public void doFilter(ServletRequest request, ServletResponse      response,     FilterChain chain)     throws IOException, ServletException    {     long start = System.currentTimeMillis();     String address =  request.getRemoteAddr();     String file = ((HttpServletRequest) request).getRequestURI();     chain.doFilter(request, response);     filterConfig.getServletContext().log(         "User access! " +               " User IP: " + address +               " Resource: " + file +          " Milliseconds used: " + (System.currentTimeMillis() -            start)      );   }   public void destroy() { }   public void init(FilterConfig filterConfig)    {     this.filterConfig = filterConfig;   } }

That completes LogFilter.java. After compiling it, place it in the application’s WEB-INF\classes directory:

 webapps   |   |__chap16        |        |__WEB-INF            |  |            |  |__web.xml            |            |__classes            |  |            |  |__LogFilter.class            |            |__lib

You can see the HTML page in this application, log.html, in Figure 16.4. When you click the “Get the message” button in log.html, your access to log.jsp is logged, and log.jsp tells you so, as shown in Figure 16.5.

image from book
Figure 16.4: The log.html page

image from book
Figure 16.5: The log.jsp page

So where did the log text go? That varies by server. On Tomcat, it goes into a log file in the Tomcat logs directory, whose name depends on the date. In this case, the log file written to is localhost_log.2006-10-26.txt, and here’s what you find in it:

 2006-10-27 11:51:04 invoker: init 2006-10-27 11:51:04 jsp: init 2006-10-27 11:51:04 StandardHost[localhost]: Installing web application at context path /webdav from URL file:C:\tomcat\jakarta-tomcat-4.0.3\webapps\webdav 2006-10-27 11:51:04 WebappLoader[/webdav]: Deploying class repositories to work directory C:\tomcat\jakarta-tomcat- 4.0.3\work\localhost\webdav 2006-10-27 11:51:04 StandardManager[/webdav]: Seeding random number generator class java.security.SecureRandom 2006-10-27 11:51:04 StandardManager[/webdav]: Seeding of random number generator has been completed 2006-10-27 11:51:04 ContextConfig[/webdav]: Added certificates -> request attribute Valve 2006-10-27 11:51:04 StandardWrapper[/webdav:default]: Loading container servlet default 2006-10-27 11:51:04 default: init 2006-10-27 11:51:04 StandardWrapper[/webdav:invoker]: Loading container servlet invoker 2006-10-27 11:51:04 invoker: init 2006-10-27 11:51:04 jsp: init 2006-10-27 11:52:00 jsp: init 2006-10-27 11:52:00 User access!  User IP: 127.0.0.1 Resource: /chap16/log.jsp Milliseconds used: 672 

As you can see, the text you wanted logged has indeed been logged, and users need not know they’ve been logged, which is useful for security purposes.



Ajax Bible
Ajax Bible
ISBN: 0470102632
EAN: 2147483647
Year: 2004
Pages: 169

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