Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/struts/util/TokenProcessor.java


1   /*
2    * $Id: TokenProcessor.java 54929 2004-10-16 16:38:42Z germuska $ 
3    *
4    * Copyright 2003-2004 The Apache Software Foundation.
5    * 
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    * 
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.struts.util;
20  
21  import java.security.MessageDigest;
22  import java.security.NoSuchAlgorithmException;
23  
24  import javax.servlet.http.HttpServletRequest;
25  import javax.servlet.http.HttpSession;
26  
27  import org.apache.struts.Globals;
28  import org.apache.struts.taglib.html.Constants;
29  
30  /**
31   * TokenProcessor is responsible for handling all token related functionality.  The 
32   * methods in this class are synchronized to protect token processing from multiple
33   * threads.  Servlet containers are allowed to return a different HttpSession object
34   * for two threads accessing the same session so it is not possible to synchronize 
35   * on the session.
36   * 
37   * @since Struts 1.1
38   */
39  public class TokenProcessor {
40  
41      /**
42       * The singleton instance of this class.
43       */
44      private static TokenProcessor instance = new TokenProcessor();
45  
46      /**
47       * Retrieves the singleton instance of this class.
48       */
49      public static TokenProcessor getInstance() {
50          return instance;
51      }
52  
53      /**
54       * Protected constructor for TokenProcessor.  Use TokenProcessor.getInstance()
55       * to obtain a reference to the processor.
56       */
57      protected TokenProcessor() {
58          super();
59      }
60  
61      /**
62       * The timestamp used most recently to generate a token value.
63       */
64      private long previous;
65  
66      /**
67       * Return <code>true</code> if there is a transaction token stored in
68       * the user's current session, and the value submitted as a request
69       * parameter with this action matches it.  Returns <code>false</code>
70       * under any of the following circumstances:
71       * <ul>
72       * <li>No session associated with this request</li>
73       * <li>No transaction token saved in the session</li>
74       * <li>No transaction token included as a request parameter</li>
75       * <li>The included transaction token value does not match the
76       *     transaction token in the user's session</li>
77       * </ul>
78       *
79       * @param request The servlet request we are processing
80       */
81      public synchronized boolean isTokenValid(HttpServletRequest request) {
82          return this.isTokenValid(request, false);
83      }
84  
85      /**
86       * Return <code>true</code> if there is a transaction token stored in
87       * the user's current session, and the value submitted as a request
88       * parameter with this action matches it.  Returns <code>false</code>
89       * <ul>
90       * <li>No session associated with this request</li>
91       * <li>No transaction token saved in the session</li>
92       * <li>No transaction token included as a request parameter</li>
93       * <li>The included transaction token value does not match the
94       *     transaction token in the user's session</li>
95       * </ul>
96       *
97       * @param request The servlet request we are processing
98       * @param reset Should we reset the token after checking it?
99       */
100     public synchronized boolean isTokenValid(
101         HttpServletRequest request,
102         boolean reset) {
103 
104         // Retrieve the current session for this request
105         HttpSession session = request.getSession(false);
106         if (session == null) {
107             return false;
108         }
109 
110         // Retrieve the transaction token from this session, and
111         // reset it if requested
112         String saved = (String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY);
113         if (saved == null) {
114             return false;
115         }
116 
117         if (reset) {
118             this.resetToken(request);
119         }
120 
121         // Retrieve the transaction token included in this request
122         String token = request.getParameter(Constants.TOKEN_KEY);
123         if (token == null) {
124             return false;
125         }
126 
127         return saved.equals(token);
128     }
129 
130     /**
131      * Reset the saved transaction token in the user's session.  This
132      * indicates that transactional token checking will not be needed
133      * on the next request that is submitted.
134      *
135      * @param request The servlet request we are processing
136      */
137     public synchronized void resetToken(HttpServletRequest request) {
138 
139         HttpSession session = request.getSession(false);
140         if (session == null) {
141             return;
142         }
143         session.removeAttribute(Globals.TRANSACTION_TOKEN_KEY);
144     }
145 
146     /**
147      * Save a new transaction token in the user's current session, creating
148      * a new session if necessary.
149      *
150      * @param request The servlet request we are processing
151      */
152     public synchronized void saveToken(HttpServletRequest request) {
153 
154         HttpSession session = request.getSession();
155         String token = generateToken(request);
156         if (token != null) {
157             session.setAttribute(Globals.TRANSACTION_TOKEN_KEY, token);
158         }
159 
160     }
161 
162     /**
163      * Generate a new transaction token, to be used for enforcing a single
164      * request for a particular transaction.
165      * 
166      * @param request The request we are processing
167      */
168     public synchronized String generateToken(HttpServletRequest request) {
169 
170         HttpSession session = request.getSession();
171         try {
172             byte id[] = session.getId().getBytes();
173             long current = System.currentTimeMillis();
174             if (current == previous) {
175                 current++;
176             }
177             previous = current;
178             byte now[] = new Long(current).toString().getBytes();
179             MessageDigest md = MessageDigest.getInstance("MD5");
180             md.update(id);
181             md.update(now);
182             return toHex(md.digest());
183         } catch (NoSuchAlgorithmException e) {
184             return null;
185         }
186 
187     }
188 
189     /**
190      * Convert a byte array to a String of hexadecimal digits and return it.
191      * @param buffer The byte array to be converted
192      */
193     private String toHex(byte buffer[]) {
194         StringBuffer sb = new StringBuffer(buffer.length * 2);
195         for (int i = 0; i < buffer.length; i++) {
196             sb.append(Character.forDigit((buffer[i] & 0xf0) >> 4, 16));
197             sb.append(Character.forDigit(buffer[i] & 0x0f, 16));
198         }
199         return sb.toString();
200     }
201 
202 }