View Javadoc

1   package com.atlassian.seraph.cookie;
2   
3   import com.atlassian.seraph.config.SecurityConfigFactory;
4   import com.atlassian.seraph.util.CookieUtils;
5   import com.atlassian.seraph.util.EncryptionUtils;
6   import org.apache.log4j.Logger;
7   
8   import java.net.URLEncoder;
9   import java.net.URLDecoder;
10  import java.io.UnsupportedEncodingException;
11  
12  /**
13   * Encrypts the username and password using password-based-encryption (MD5 and DES).
14   */
15  public class EncryptedCookieEncoder implements CookieEncoder
16  {
17      private static final Logger LOG = Logger.getLogger(EncryptedCookieEncoder.class);
18  
19      private static final String URL_ENCODING = "UTF-8";
20  
21      private static final String SEPARATOR = "^^^";
22      
23      private final EncryptionUtils encryptionUtils;
24  
25      public EncryptedCookieEncoder()
26      {
27          this(SecurityConfigFactory.getInstance().getCookieEncoding());
28      }
29  
30      protected EncryptedCookieEncoder(String password)
31      {
32          if (password == null || password.length() == 0)
33          {
34              throw new IllegalArgumentException("The password must be specified");
35          }
36          encryptionUtils = new EncryptionUtils();
37          encryptionUtils.setPassword(password);
38      }
39  
40      public String encodePasswordCookie(String username, String password, String encoding)
41      {
42          StringBuffer sb = new StringBuffer();
43          sb.append(username).append(SEPARATOR).append(password);
44          return escapeInvalidCookieCharacters(encryptionUtils.encrypt(sb.toString()));
45      }
46  
47      public String[] decodePasswordCookie(String cookieVal, String encoding)
48      {
49          final String[] result = new String[2];
50          try
51          {
52              final String text = encryptionUtils.decrypt(unescapeInvalidCookieCharacters(cookieVal));
53              int pos = text.indexOf(SEPARATOR);
54              if (pos < 0)
55              {
56                  LOG.info("Successfully decrypted password cookie, but decrypted value '" + text + "' is invalid because separator ('" +
57                      SEPARATOR + "') was not found. Returning null.");
58                  return null;
59              }
60              result[0] = text.substring(0, pos);
61              result[1] = text.substring(pos + SEPARATOR.length());
62          }
63          catch (RuntimeException ex)
64          {
65              LOG.info("Password cookie could not be decrypted, trying old insecure method of decoding it");
66              return CookieUtils.decodePasswordCookie(cookieVal, encoding);
67          }
68          return result;
69      }
70  
71      /**
72       * Escape invalid cookie characters, see SER-117
73       *
74       * @param s the String to escape characters for.
75       * @return the encoded string.
76       * @see #unescapeInvalidCookieCharacters(String)
77       */
78      private static String escapeInvalidCookieCharacters(final String s)
79      {
80          try
81          {
82              return URLEncoder.encode(s, URL_ENCODING);
83          }
84          catch (UnsupportedEncodingException e)
85          {
86              LOG.fatal("UTF-8 encoding unsupported !!?!! How is that possible?", e);
87              throw new RuntimeException(e);
88          }
89      }
90  
91      /**
92       * Un-escape invalid cookie characters, see SER-117
93       *
94       * @param s the String to escape characters for.
95       * @return the encoded string.
96       * @see #escapeInvalidCookieCharacters(String)
97       */
98      private static String unescapeInvalidCookieCharacters(final String s)
99      {
100         try
101         {
102             return URLDecoder.decode(s, URL_ENCODING);
103         }
104         catch (UnsupportedEncodingException e)
105         {
106             LOG.fatal("UTF-8 encoding unsupported !!?!! How is that possible?", e);
107             throw new RuntimeException(e);
108         }
109     }
110 }