/hudson-core/src/main/java/hudson/security/csrf/CrumbIssuer.java

http://github.com/hudson/hudson · Java · 155 lines · 64 code · 18 blank · 73 comment · 10 complexity · 3d3fb1a39b3bd4e3a51cb363b75c3238 MD5 · raw file

  1. /**
  2. * Copyright (c) 2008-2009 Yahoo! Inc.
  3. * All rights reserved.
  4. * The copyrights to the contents of this file are licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php)
  5. */
  6. package hudson.security.csrf;
  7. import javax.servlet.ServletRequest;
  8. import org.kohsuke.stapler.Stapler;
  9. import org.kohsuke.stapler.export.Exported;
  10. import org.kohsuke.stapler.export.ExportedBean;
  11. import hudson.DescriptorExtensionList;
  12. import hudson.ExtensionPoint;
  13. import hudson.model.Api;
  14. import hudson.model.Describable;
  15. import hudson.model.Descriptor;
  16. import hudson.model.Hudson;
  17. import hudson.util.MultipartFormDataParser;
  18. /**
  19. * A CrumbIssuer represents an algorithm to generate a nonce value, known as a
  20. * crumb, to counter cross site request forgery exploits. Crumbs are typically
  21. * hashes incorporating information that uniquely identifies an agent that sends
  22. * a request, along with a guarded secret so that the crumb value cannot be
  23. * forged by a third party.
  24. *
  25. * @author dty
  26. * @see http://en.wikipedia.org/wiki/XSRF
  27. */
  28. @ExportedBean
  29. public abstract class CrumbIssuer implements Describable<CrumbIssuer>, ExtensionPoint {
  30. private static final String CRUMB_ATTRIBUTE = CrumbIssuer.class.getName() + "_crumb";
  31. /**
  32. * Get the name of the request parameter the crumb will be stored in. Exposed
  33. * here for the remote API.
  34. */
  35. @Exported
  36. public String getCrumbRequestField() {
  37. return getDescriptor().getCrumbRequestField();
  38. }
  39. /**
  40. * Get a crumb value based on user specific information in the current request.
  41. * Intended for use only by the remote API.
  42. * @return
  43. */
  44. @Exported
  45. public String getCrumb() {
  46. return getCrumb(Stapler.getCurrentRequest());
  47. }
  48. /**
  49. * Get a crumb value based on user specific information in the request.
  50. * @param request
  51. * @return
  52. */
  53. public String getCrumb(ServletRequest request) {
  54. String crumb = null;
  55. if (request != null) {
  56. crumb = (String) request.getAttribute(CRUMB_ATTRIBUTE);
  57. }
  58. if (crumb == null) {
  59. crumb = issueCrumb(request, getDescriptor().getCrumbSalt());
  60. if (request != null) {
  61. if ((crumb != null) && crumb.length()>0) {
  62. request.setAttribute(CRUMB_ATTRIBUTE, crumb);
  63. } else {
  64. request.removeAttribute(CRUMB_ATTRIBUTE);
  65. }
  66. }
  67. }
  68. return crumb;
  69. }
  70. /**
  71. * Create a crumb value based on user specific information in the request.
  72. * The crumb should be generated by building a cryptographic hash of:
  73. * <ul>
  74. * <li>relevant information in the request that can uniquely identify the client
  75. * <li>the salt value
  76. * <li>an implementation specific guarded secret.
  77. * </ul>
  78. *
  79. * @param request
  80. * @param salt
  81. * @return
  82. */
  83. protected abstract String issueCrumb(ServletRequest request, String salt);
  84. /**
  85. * Get a crumb from a request parameter and validate it against other data
  86. * in the current request. The salt and request parameter that is used is
  87. * defined by the current configuration.
  88. *
  89. * @param request
  90. * @return
  91. */
  92. public boolean validateCrumb(ServletRequest request) {
  93. CrumbIssuerDescriptor<CrumbIssuer> desc = getDescriptor();
  94. String crumbField = desc.getCrumbRequestField();
  95. String crumbSalt = desc.getCrumbSalt();
  96. return validateCrumb(request, crumbSalt, request.getParameter(crumbField));
  97. }
  98. /**
  99. * Get a crumb from multipart form data and validate it against other data
  100. * in the current request. The salt and request parameter that is used is
  101. * defined by the current configuration.
  102. *
  103. * @param request
  104. * @param parser
  105. * @return
  106. */
  107. public boolean validateCrumb(ServletRequest request, MultipartFormDataParser parser) {
  108. CrumbIssuerDescriptor<CrumbIssuer> desc = getDescriptor();
  109. String crumbField = desc.getCrumbRequestField();
  110. String crumbSalt = desc.getCrumbSalt();
  111. return validateCrumb(request, crumbSalt, parser.get(crumbField));
  112. }
  113. /**
  114. * Validate a previously created crumb against information in the current request.
  115. *
  116. * @param request
  117. * @param salt
  118. * @param crumb The previously generated crumb to validate against information in the current request
  119. * @return
  120. */
  121. public abstract boolean validateCrumb(ServletRequest request, String salt, String crumb);
  122. /**
  123. * Access global configuration for the crumb issuer.
  124. */
  125. public CrumbIssuerDescriptor<CrumbIssuer> getDescriptor() {
  126. return (CrumbIssuerDescriptor<CrumbIssuer>) Hudson.getInstance().getDescriptorOrDie(getClass());
  127. }
  128. /**
  129. * Returns all the registered {@link CrumbIssuer} descriptors.
  130. */
  131. public static DescriptorExtensionList<CrumbIssuer, Descriptor<CrumbIssuer>> all() {
  132. return Hudson.getInstance().<CrumbIssuer, Descriptor<CrumbIssuer>>getDescriptorList(CrumbIssuer.class);
  133. }
  134. public Api getApi() {
  135. return new Api(this);
  136. }
  137. }