1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
53
54
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
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
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
154 String token = (String) request.getParameter(Globals.SYNC_TOKEN_PARAMETER);
155 if (token == null) {
156 return (false);
157 }
158
159
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 }