DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=29943>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=29943

TokenProcessor generates double tokens on fast processors

           Summary: TokenProcessor generates double tokens on fast
                    processors
           Product: Struts
           Version: Nightly Build
          Platform: Other
        OS/Version: Other
            Status: NEW
          Severity: Minor
          Priority: Other
         Component: Utilities
        AssignedTo: [EMAIL PROTECTED]
        ReportedBy: [EMAIL PROTECTED]


On really fast processors the TokenProcessor may generate the same token twice.
This happens when System.currentTimeMillis() returns the same amount multiple
times. I have seen this happen on really fast systems.

Note that it is really unlikely that the bug will occur in reality since the
same user would have to request 2 forms simultaneously.

The following patch solves the bug anyway by using a random generator.

I have made more small changes that are not directly related to this bug: 
- I did not understand why the existing implementation catches
IllegalStateException, so I removed it. Please keep the catch when I missed
something (or just to be sure).
- I did not understand why the existing implementation silently suppresses
NoSuchAlgorithmException, so I added some behaviour.
- The toHex method has been slightly improved.


        /** A random generator to prevent double tokens on really fast systems. */
        private Random randomGenerator;


        /**
         * Generate a new transaction token, to be used for enforcing a single
         * request for a particular transaction.
         * 
         * @param request The request we are processing
         * @return the generated token
         */
        private String generateToken(HttpServletRequest request) {
                // The following data is used for a token: 
                // - id of the session
                // - current time
                // - some random bytes, on really fast machines the same
                //   time is often returned twice or more
                //   Note that a random is used instead of a sequence number
                //   to prevent the use of another synchronisation point.
                
                HttpSession session = request.getSession();
                byte id[] = session.getId().getBytes();
                byte now[] = new 
Long(System.currentTimeMillis()).toString().getBytes();
                byte rnd[] = new byte[] { (byte) randomGenerator.nextInt(), (byte)
randomGenerator.nextInt() };

                try {
                        MessageDigest md = MessageDigest.getInstance("MD5");
                        md.update(id);
                        md.update(now);
                        md.update(rnd);
                        return toHex(md.digest());

                } catch (NoSuchAlgorithmException e) {
                        throw new RuntimeException("Not a valid JRE: MD5 algorithm not 
supported");
                }
        }

        /**
         * Convert a byte array to a String of hexadecimal digits and return it.
         * @param buffer The byte array to be converted
         * @return a hex string representation of the byte array
         */
        private static String toHex(byte buffer[]) {
                StringBuffer sb = new StringBuffer(buffer.length * 2);
                for (int i = 0; i < buffer.length; i++) {
                        sb.append(Character.forDigit((buffer[i] & 0xf0) >> 4, 16));
                        sb.append(Character.forDigit(buffer[i] & 0x0f, 16));
                }
                return sb.toString();
        }

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to