View Javadoc

1   package com.atlassian.xwork;
2   
3   import javax.servlet.http.HttpServletRequest;
4   import javax.servlet.http.HttpSession;
5   
6   import com.atlassian.xwork.interceptors.XsrfTokenInterceptor;
7   
8   import java.util.Random;
9   
10  /**
11   * Simple implementation of XsrfTokenGenerator that stores a unique value in the session. The session ID
12   * itself isn't used because we don't want to risk compromising the entire session in case we don't protect
13   * the XSRF token diligently enough.
14   *
15   * <p>Tokens are chosen to be reasonably unique (60 bits) with reasonably short representations (base64 encoded).
16   */
17  public class SimpleXsrfTokenGenerator implements XsrfTokenGenerator
18  {
19      public static final String TOKEN_SESSION_KEY = "atlassian.xsrf.token";
20  
21      // Random is static so we don't get problems with timing attacks because new TokenGenerator().generateToken()
22      // will generate the same number if requests come in the same millisecond.
23      private static Random random = new Random();
24  
25      public String generateToken(HttpServletRequest request)
26      {
27          HttpSession session = request.getSession();
28          String token = (String) session.getAttribute(TOKEN_SESSION_KEY);
29  
30          if (token == null)
31          {
32              token = createToken();
33              session.setAttribute(TOKEN_SESSION_KEY, token);
34          }
35  
36          return token;
37      }
38      
39      public String getXsrfTokenName()
40      {
41          return XsrfTokenInterceptor.REQUEST_PARAM_NAME;
42      }
43  
44      public boolean validateToken(HttpServletRequest request, String token)
45      {
46          return token != null && token.equals(request.getSession(true).getAttribute(TOKEN_SESSION_KEY));
47      }
48  
49      private synchronized String createToken()
50      {
51          return SimpleEncoder.encode(random.nextLong());
52      }
53  
54      /**
55       * Turns a long into a ten-character string by base64-encoding the least significant 60 bits.
56       */
57      private static class SimpleEncoder
58      {
59          private static final char[] MAPPING;
60  
61          static
62          {
63              MAPPING = new char[64];
64  
65              int i = 0;
66  
67              for (char c = 'A'; c <= 'Z'; c++, i++)
68              {
69                  MAPPING[i] = c;
70              }
71  
72              for (char c = 'a'; c <= 'z'; c++, i++)
73              {
74                  MAPPING[i] = c;
75              }
76  
77              for (char c = '0'; c <= '9'; c++, i++)
78              {
79                  MAPPING[i] = c;
80              }
81  
82              MAPPING[62] = '_';
83              MAPPING[63] = '-';
84          }
85  
86          public static String encode(long l)
87          {
88              char[] out = new char[10];
89  
90              for (int i = 0; i < 10; i++)
91              {
92                  out[i] =  MAPPING[(int) (l & 63)];
93                  l = l >>> 6;
94              }
95  
96              return new String(out);
97          }
98      }
99  }