PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/jira-project/jira-components/jira-core/src/main/java/com/atlassian/jira/web/filters/accesslog/AtlassianSessionIdUtil.java

https://bitbucket.org/ahmed_bilal_360factors/jira7-core
Java | 185 lines | 109 code | 22 blank | 54 comment | 28 complexity | f383cebaa3f30ab475a72cadb254365e MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.atlassian.jira.web.filters.accesslog;
  2. import org.apache.commons.lang.StringUtils;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import javax.servlet.http.HttpSession;
  8. import java.io.UnsupportedEncodingException;
  9. import java.security.MessageDigest;
  10. import java.security.NoSuchAlgorithmException;
  11. import java.util.zip.CRC32;
  12. /**
  13. * You can use this to generate a hash of the JSESSIONID so we can get session specific information into logs without
  14. * giving away the keys to the house!
  15. *
  16. * @since v3.13.2
  17. */
  18. public class AtlassianSessionIdUtil {
  19. public static final String ASESSIONID_NAME = "ASESSIONID";
  20. public static final String JSESSIONID_NAME = "JSESSIONID";
  21. private static final Logger log = LoggerFactory.getLogger(AtlassianSessionIdUtil.class);
  22. /**
  23. * This will look for an existing HTTP session and if its present, it will generate a ASESSIONID base on a hash of
  24. * the session's id.
  25. * <p>
  26. * It will check in the session for such a beast, and hence only calculate it once and its lifecycle is therefore
  27. * properly tied to the session itself.
  28. * <p>
  29. * We can then safely put this ASESSIONID in the logs and let someone upstream, say in a proxy, examine it.
  30. * <p>
  31. * CALLING NOTES - This method MUST be invoked before any content output is sent to the client. It sets cookies
  32. * etc. and hence it needs the response to be be in a suitable state. It is expected that this method will be
  33. * called early on in say a filter.
  34. *
  35. * @param httpServletRequest the HTTP request
  36. * @param httpServletResponse the HTTP response
  37. * @return the atlassian session id hash or null if there is no session (it does not exist) or if the hash of the
  38. * session id cannot be generated (e.g. if the sessions id is null, which should not happen)
  39. */
  40. public static String generateAtlassianSessionHash(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
  41. String ASESSIONID;
  42. // Without creating a session, have we got an ASESSIONID value available?
  43. HttpSession session = httpServletRequest.getSession(false);
  44. if (session == null) {
  45. // Since there is no session, we should not generate a new ASESSIONID cookie
  46. return null;
  47. } else {
  48. // Retrieve the ASESSIONID value from the session
  49. ASESSIONID = (String) session.getAttribute(ASESSIONID_NAME);
  50. }
  51. // If we do not have a ASESSIONID stored, but have a session then we need to generate ASESSIONID and store it in the session
  52. if (ASESSIONID == null) {
  53. // Lets make a hash of the session's id
  54. ASESSIONID = generateNewASESSIONID(session);
  55. }
  56. //
  57. // we only allow the digest value part to escape this function
  58. return getDigestEncodedValue(ASESSIONID);
  59. }
  60. private static String generateNewASESSIONID(HttpSession session) {
  61. final String sessionId = session.getId();
  62. String ASESSIONID = generateASESSIONID(sessionId);
  63. // If generated ASESSIONID is null then we should print a warning and not do anything
  64. if (ASESSIONID == null) {
  65. // Print with debug severity as if this happens it is likely to happen with every request, and we do not
  66. // want to fill up the logs
  67. if (log.isDebugEnabled()) {
  68. log.debug("Session with id '" + sessionId + "' generated a null hash. Not setting ASESSIONID cookie or header.");
  69. }
  70. return null;
  71. }
  72. final String sessionIdHex = smartHexEncode(sessionId, getinUTF8(sessionId));
  73. ASESSIONID = ASESSIONID + '-' + sessionIdHex;
  74. // Store the value in the session so that we do not have to calculate it again
  75. session.setAttribute(ASESSIONID_NAME, ASESSIONID);
  76. return ASESSIONID;
  77. }
  78. /**
  79. * This will generate a hashed version of the passed in HttpSession sessionId
  80. * <p>
  81. * It will be returned in the form <i>digestEncodedValue</i>-<i>hexEncodedValue</i>
  82. *
  83. * @param sessionId the session id string
  84. * @return a hashed version of that session string or null if the input is null
  85. */
  86. public static String generateASESSIONID(final String sessionId) {
  87. if (sessionId == null) {
  88. return null;
  89. }
  90. final byte[] bytes = getinUTF8(sessionId);
  91. MessageDigest md = getMessageDigest("SHA");
  92. if (md == null) {
  93. md = getMessageDigest("MD5");
  94. }
  95. if (md == null) {
  96. return null;
  97. }
  98. md.update(bytes);
  99. byte[] digest = md.digest();
  100. return encode(digest);
  101. }
  102. /**
  103. * Takes a generated ASESSION id value in the form <i>digestEncodedValue</i>-<i>hexEncodedValue</i> and returns the
  104. * digest encoded part
  105. *
  106. * @param asessionId the full asessionId in play
  107. * @return null if its blank or the part before last '-' character
  108. */
  109. private static String getDigestEncodedValue(final String asessionId) {
  110. if (StringUtils.isBlank(asessionId)) {
  111. return null;
  112. }
  113. int index = asessionId.lastIndexOf('-');
  114. if (index == -1 || index == 0) {
  115. return null;
  116. }
  117. return asessionId.substring(0, index);
  118. }
  119. private static byte[] getinUTF8(final String sessionId) {
  120. byte[] input = null;
  121. try {
  122. input = sessionId.getBytes("UTF-8");
  123. } catch (UnsupportedEncodingException e) {
  124. // just not going to happen since every implementation of the Java platform is required to support UTF-8
  125. //
  126. // if you don't believe me see http://java.sun.com/j2se/1.4.2/docs/api/java/nio/charset/Charset.html
  127. }
  128. return input;
  129. }
  130. private static String smartHexEncode(final String sessionId, final byte[] bytes) {
  131. // some apps servers such as Tomcat give us the sessionId already in hex so lets double check that
  132. boolean isAllHex = true;
  133. for (char c : sessionId.toCharArray()) {
  134. if (!isHex(c)) {
  135. isAllHex = false;
  136. break;
  137. }
  138. }
  139. if (isAllHex) {
  140. return sessionId;
  141. }
  142. StringBuilder sb = new StringBuilder();
  143. for (byte aByte : bytes) {
  144. sb.append(Integer.toHexString(aByte));
  145. }
  146. return sb.toString();
  147. }
  148. private static boolean isHex(final char c) {
  149. return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
  150. }
  151. private static String encode(final byte[] bytes) {
  152. CRC32 crc32 = new CRC32();
  153. crc32.update(bytes);
  154. return Long.toString(crc32.getValue(), Character.MAX_RADIX);
  155. }
  156. private static MessageDigest getMessageDigest(String digestName) {
  157. try {
  158. return MessageDigest.getInstance(digestName);
  159. } catch (NoSuchAlgorithmException e) {
  160. return null;
  161. }
  162. }
  163. }