File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\security\csrf\CrumbIssuer.java.html

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
8 import javax.servlet.ServletRequest;
9
10 import hudson.init.Initializer;
11 import jenkins.model.Jenkins;
12 import org.kohsuke.stapler.Stapler;
13 import org.kohsuke.stapler.StaplerRequest;
14 import org.kohsuke.stapler.WebApp;
15 import org.kohsuke.stapler.export.Exported;
16 import org.kohsuke.stapler.export.ExportedBean;
17
18 import hudson.DescriptorExtensionList;
19 import hudson.ExtensionPoint;
20 import hudson.model.Api;
21 import hudson.model.Describable;
22 import hudson.model.Descriptor;
23 import hudson.util.MultipartFormDataParser;
24 import java.io.IOException;
25 import java.io.OutputStream;
26 import javax.servlet.ServletException;
27 import org.kohsuke.accmod.Restricted;
28 import org.kohsuke.accmod.restrictions.NoExternalUse;
29 import org.kohsuke.stapler.QueryParameter;
30 import org.kohsuke.stapler.StaplerResponse;
31
32 /**
33 * A CrumbIssuer represents an algorithm to generate a nonce value, known as a
34 * crumb, to counter cross site request forgery exploits. Crumbs are typically
35 * hashes incorporating information that uniquely identifies an agent that sends
36 * a request, along with a guarded secret so that the crumb value cannot be
37 * forged by a third party.
38 *
39 * @author dty
40 * @see http://en.wikipedia.org/wiki/XSRF
41 */
42 @ExportedBean
43 public abstract class CrumbIssuer implements Describable<CrumbIssuer>, ExtensionPoint {
44
45 private static final String CRUMB_ATTRIBUTE = CrumbIssuer.class.getName() + "_crumb";
46
47 /**
48 * Get the name of the request parameter the crumb will be stored in. Exposed
49 * here for the remote API.
50 */
51 @Exported
52 public String getCrumbRequestField() {
53 return getDescriptor().getCrumbRequestField();
54 }
55
56 /**
57 * Get a crumb value based on user specific information in the current request.
58 * Intended for use only by the remote API.
59 * @return
60 */
61 @Exported
62 public String getCrumb() {
63 return getCrumb(Stapler.getCurrentRequest());
64 }
65
66 /**
67 * Get a crumb value based on user specific information in the request.
68 * @param request
69 * @return
70 */
71 public String getCrumb(ServletRequest request) {
72 String crumb = null;
73 if (request != null) {
74 crumb = (String) request.getAttribute(CRUMB_ATTRIBUTE);
75 }
76 if (crumb == null) {
77 crumb = issueCrumb(request, getDescriptor().getCrumbSalt());
78 if (request != null) {
79 if ((crumb != null) && crumb.length()>0) {
80 request.setAttribute(CRUMB_ATTRIBUTE, crumb);
81 } else {
82 request.removeAttribute(CRUMB_ATTRIBUTE);
83 }
84 }
85 }
86
87 return crumb;
88 }
89
90 /**
91 * Create a crumb value based on user specific information in the request.
92 * The crumb should be generated by building a cryptographic hash of:
93 * <ul>
94 * <li>relevant information in the request that can uniquely identify the client
95 * <li>the salt value
96 * <li>an implementation specific guarded secret.
97 * </ul>
98 *
99 * @param request
100 * @param salt
101 * @return
102 */
103 protected abstract String issueCrumb(ServletRequest request, String salt);
104
105 /**
106 * Get a crumb from a request parameter and validate it against other data
107 * in the current request. The salt and request parameter that is used is
108 * defined by the current configuration.
109 *
110 * @param request
111 * @return
112 */
113 public boolean validateCrumb(ServletRequest request) {
114 CrumbIssuerDescriptor<CrumbIssuer> desc = getDescriptor();
115 String crumbField = desc.getCrumbRequestField();
116 String crumbSalt = desc.getCrumbSalt();
117
118 return validateCrumb(request, crumbSalt, request.getParameter(crumbField));
119 }
120
121 /**
122 * Get a crumb from multipart form data and validate it against other data
123 * in the current request. The salt and request parameter that is used is
124 * defined by the current configuration.
125 *
126 * @param request
127 * @param parser
128 * @return
129 */
130 public boolean validateCrumb(ServletRequest request, MultipartFormDataParser parser) {
131 CrumbIssuerDescriptor<CrumbIssuer> desc = getDescriptor();
132 String crumbField = desc.getCrumbRequestField();
133 String crumbSalt = desc.getCrumbSalt();
134
135 return validateCrumb(request, crumbSalt, parser.get(crumbField));
136 }
137
138 /**
139 * Validate a previously created crumb against information in the current request.
140 *
141 * @param request
142 * @param salt
143 * @param crumb The previously generated crumb to validate against information in the current request
144 * @return
145 */
146 public abstract boolean validateCrumb(ServletRequest request, String salt, String crumb);
147
148 /**
149 * Access global configuration for the crumb issuer.
150 */
151 public CrumbIssuerDescriptor<CrumbIssuer> getDescriptor() {
152 return (CrumbIssuerDescriptor<CrumbIssuer>) Jenkins.getInstance().getDescriptorOrDie(getClass());
153 }
154
155 /**
156 * Returns all the registered {@link CrumbIssuer} descriptors.
157 */
158 public static DescriptorExtensionList<CrumbIssuer, Descriptor<CrumbIssuer>> all() {
159 return Jenkins.getInstance().<CrumbIssuer, Descriptor<CrumbIssuer>>getDescriptorList(CrumbIssuer.class);
160 }
161
162 public Api getApi() {
163 return new RestrictedApi(this);
164 }
165
166 /**
167 * Sets up Stapler to use our crumb issuer.
168 */
169 @Initializer
170 public static void initStaplerCrumbIssuer() {
171 WebApp.get(Jenkins.getInstance().servletContext).setCrumbIssuer(new org.kohsuke.stapler.CrumbIssuer() {
172 @Override
173 public String issueCrumb(StaplerRequest request) {
174 CrumbIssuer ci = Jenkins.getInstance().getCrumbIssuer();
175 return ci!=null ? ci.getCrumb(request) : DEFAULT.issueCrumb(request);
176 }
177
178 @Override
179 public void validateCrumb(StaplerRequest request, String submittedCrumb) {
180 CrumbIssuer ci = Jenkins.getInstance().getCrumbIssuer();
181 if (ci==null) {
182 DEFAULT.validateCrumb(request,submittedCrumb);
183 } else {
184 if (!ci.validateCrumb(request, ci.getDescriptor().getCrumbSalt(), submittedCrumb))
185 throw new SecurityException("Crumb didn't match");
186 }
187 }
188 });
189 }
190
191 @Restricted(NoExternalUse.class)
192 public static class RestrictedApi extends Api {
193
194 RestrictedApi(CrumbIssuer instance) {
195 super(instance);
196 }
197
198 @Override public void doXml(StaplerRequest req, StaplerResponse rsp, @QueryParameter String xpath, @QueryParameter String wrapper, @QueryParameter String tree, @QueryParameter int depth) throws IOException, ServletException {
199 String text;
200 CrumbIssuer ci = (CrumbIssuer) bean;
201 if ("/*/crumbRequestField/text()".equals(xpath)) { // old FullDuplexHttpStream
202 text = ci.getCrumbRequestField();
203 } else if ("/*/crumb/text()".equals(xpath)) { // ditto
204 text = ci.getCrumb();
205 } else if ("concat(//crumbRequestField,\":\",//crumb)".equals(xpath)) { // new FullDuplexHttpStream; Main
206 text = ci.getCrumbRequestField() + ':' + ci.getCrumb();
207 } else if ("concat(//crumbRequestField,'=',//crumb)".equals(xpath)) { // NetBeans
208 if (ci.getCrumbRequestField().startsWith(".")) {
209 text = ci.getCrumbRequestField() + '=' + ci.getCrumb();
210 } else {
211 text = null;
212 }
213 } else {
214 text = null;
215 }
216 if (text != null) {
217 OutputStream o = rsp.getCompressedOutputStream(req);
218 try {
219 rsp.setContentType("text/plain;charset=UTF-8");
220 o.write(text.getBytes("UTF-8"));
221 } finally {
222 o.close();
223 }
224 } else {
225 super.doXml(req, rsp, xpath, wrapper, tree, depth);
226 }
227 }
228
229 }
230
231 }
232