View Javadoc

1   /*
2    * $Id: DuplicateRequestFilter.java 269 2005-08-10 17:49:22Z josem $
3    *
4    * Tarsis
5    * Copyright (C) 2002 Talika Open Source Group
6    *
7    * This program is free software; you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program; if not, write to the Free Software
19   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20   *
21   */
22  
23  package org.talika.tarsis.filters.duplicate;
24  
25  import java.io.IOException;
26  import java.security.MessageDigest;
27  import java.security.NoSuchAlgorithmException;
28  
29  import javax.servlet.FilterChain;
30  import javax.servlet.ServletException;
31  import javax.servlet.ServletRequest;
32  import javax.servlet.ServletResponse;
33  import javax.servlet.http.HttpServletRequest;
34  import javax.servlet.http.HttpSession;
35  
36  import org.talika.tarsis.Globals;
37  import org.talika.tarsis.command.Command;
38  import org.talika.tarsis.filters.CommandFilter;
39  
40  /**
41   * <code>DuplicateRequestFilter</code> checks if command is dulicable and then checks
42   * if command request is duplicated.
43   *
44   * @author  Jose M. Palomar
45   * @version $Revision: 269 $
46   *
47   * @todo Move to org.talika.tarsis.filters package.
48   */
49  
50  public final class DuplicateRequestFilter extends CommandFilter {
51  
52      // Fields
53  
54      // Methods
55      /**
56       * Checks if command is dulicable and then cheks if command request is
57       * duplicated.<br>
58       *
59       * @param servletRequest ServletRequest the <code>ServletRequest</code> object
60       * that contains the client's request.
61       * @param servletResponse ServletResponse the <code>ServletResponse</code> object
62       * that contains the servlet's response.
63       * @param filterChain FilterChain invocation chain of filtered request.
64       * @throws IOException if an input or output exception occurs
65       * @throws ServletException if an exception has occurred that interferes with the
66       * filter's normal operation
67       * @see javax.servlet.Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
68       */
69      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
70      FilterChain filterChain)
71      throws IOException, ServletException {
72  
73          if (getLogger().isDebugEnabled()) {
74              getLogger().logDebug(getFilterConfig().getFilterName() + ": invoked");
75          }
76  
77          try {
78              Command cmd = findCommand(servletRequest);
79              if (cmd != null) {
80                  if (!cmd.isDuplicable()) {
81                      if (!isTokenValid((HttpServletRequest) servletRequest)) {
82                          throw new DuplicateRequestException("Duplicated request");
83                      }
84                  }
85              }
86              saveToken((HttpServletRequest) servletRequest);
87          }
88          catch (Throwable t) {
89              throw new ServletException(t);
90          }
91  
92          filterChain.doFilter(servletRequest, servletResponse);
93  
94      }
95  
96      // Token methods
97      /**
98       * Generates a token for given request.<br>
99       * <br>
100      * Borrowed from Action.java (Jakarta Struts).
101      *
102      * @param request HttpServletRequest the <code>HttpServletRequest</code> object
103      * that contains the client's request.
104      * @return String token generated from request.
105      */
106     protected String generateToken(HttpServletRequest request) {
107 
108         HttpSession session = request.getSession();
109         try {
110             byte[] id = session.getId().getBytes();
111             byte[] now =
112                 new Long(System.currentTimeMillis()).toString().getBytes();
113             MessageDigest md = MessageDigest.getInstance("MD5");
114             md.update(id);
115             md.update(now);
116             return (toHex(md.digest()));
117         }
118         catch (IllegalStateException e) {
119             return (null);
120         }
121         catch (NoSuchAlgorithmException e) {
122             return (null);
123         }
124 
125     }
126 
127     /**
128      * Checks if token is valid.<br>
129      * <br>
130      * <ol>
131      * <li>First tries to obtain saved token from <code>HttpSession</code>.</li>
132      * <li>Then tries to obtain token from <code>HttpServletRequest</code>.</li>
133      * <li>Last compare session token with request token.</li>
134      * </ol>
135      *
136      * @param request HttpServletRequest the <code>HttpServletRequest</code> object
137      * that contains the client's request.
138      * @return boolean
139      */
140     protected boolean isTokenValid(HttpServletRequest request) {
141 
142         // Retrieve the saved transaction token from our session
143         HttpSession session = request.getSession(false);
144         if (session == null) {
145             return (false);
146         }
147 
148         String saved = (String) session.getAttribute(Globals.SYNC_TOKEN_ATTR);
149         if (saved == null) {
150             return (false);
151         }
152 
153         // Retrieve the transaction token included in this request
154         String token = (String) request.getParameter(Globals.SYNC_TOKEN_PARAMETER);
155         if (token == null) {
156             return (false);
157         }
158 
159         // Do the values match?
160         return (saved.equals(token));
161 
162     }
163 
164     /**
165      * Resets token saved in client's <code>HttpSession</code>.
166      *
167      * @param request HttpServletRequest the <code>HttpServletRequest</code> object
168      * that contains the client's request.
169      */
170     protected void resetToken(HttpServletRequest request) {
171 
172         HttpSession session = request.getSession(false);
173         if (session == null) {
174             return;
175         }
176         session.removeAttribute(Globals.SYNC_TOKEN_ATTR);
177 
178     }
179 
180     /**
181      * Saves tokan in client's <code>HttpSession</code>.
182      *
183      * @param request HttpServletRequest the <code>HttpServletRequest</code> object
184      * that contains the client's request.
185      */
186     protected void saveToken(HttpServletRequest request) {
187 
188         HttpSession session = request.getSession();
189         String token = generateToken(request);
190         if (token != null) {
191             session.setAttribute(Globals.SYNC_TOKEN_ATTR, token);
192         }
193 
194     }
195 
196     /**
197      * Converts an array of bytes in an hexadecimal <code>String</code>.
198      *
199      * @param buffer byte[] array to convert.
200      * @return String a <code>String</code> resulting from converting array of bytes.
201      */
202     private String toHex(byte[] buffer) {
203 
204         StringBuffer sb = new StringBuffer();
205         for (int i = 0; i < buffer.length; i++) {
206             sb.append(Integer.toHexString((int) buffer[i] & 0xff));
207         }
208         return (sb.toString());
209 
210     }
211 
212 }