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

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Jene Jasper, Tom Huybrechts
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson.util;
25
26 import static hudson.Util.fixEmpty;
27 import hudson.EnvVars;
28 import hudson.FilePath;
29 import hudson.ProxyConfiguration;
30 import hudson.Util;
31 import hudson.model.AbstractProject;
32 import jenkins.model.Jenkins;
33 import hudson.model.Item;
34 import hudson.security.Permission;
35 import hudson.security.AccessControlled;
36
37 import java.io.BufferedReader;
38 import java.io.File;
39 import java.io.IOException;
40 import java.io.InputStreamReader;
41 import java.net.HttpURLConnection;
42 import java.net.URL;
43 import java.net.URLConnection;
44 import java.util.Locale;
45
46 import javax.servlet.ServletException;
47
48 import org.kohsuke.stapler.StaplerRequest;
49 import org.kohsuke.stapler.StaplerResponse;
50 import org.acegisecurity.AccessDeniedException;
51 import org.kohsuke.stapler.Stapler;
52
53 /**
54 * Base class that provides the framework for doing on-the-fly form field validation.
55 *
56 * <p>
57 * The {@link #check()} method is to be implemented by derived classes to perform
58 * the validation. See hudson-behavior.js 'validated' CSS class and 'checkUrl' attribute.
59 *
60 * @author Kohsuke Kawaguchi
61 * @deprecated as of 1.294
62 * Use {@link FormValidation} as a return value in your check method.
63 */
64 public abstract class FormFieldValidator {
65 public static final Permission CHECK = Jenkins.ADMINISTER;
66
67 protected final StaplerRequest request;
68 protected final StaplerResponse response;
69 /**
70 * Permission to check, or null if this check doesn't require any permission.
71 */
72 protected final Permission permission;
73
74 /**
75 * The object to which the permission is checked against.
76 * If {@link #permission} is non-null, must be non-null.
77 */
78 protected final AccessControlled subject;
79
80 /**
81 * @param adminOnly
82 * Pass true to only let admin users to run the check. This is necessary
83 * for security reason, so that unauthenticated user cannot obtain sensitive
84 * information or run a process that may have side-effect.
85 */
86 protected FormFieldValidator(StaplerRequest request, StaplerResponse response, boolean adminOnly) {
87 this(request, response, adminOnly? Jenkins.getInstance():null, adminOnly?CHECK:null);
88 }
89
90 /**
91 * @deprecated
92 * Use {@link #FormFieldValidator(Permission)} and remove {@link StaplerRequest} and {@link StaplerResponse}
93 * from your "doCheck..." method parameter
94 */
95 protected FormFieldValidator(StaplerRequest request, StaplerResponse response, Permission permission) {
96 this(request,response, Jenkins.getInstance(),permission);
97 }
98
99 /**
100 * @param permission
101 * Permission needed to perform this validation, or null if no permission is necessary.
102 */
103 protected FormFieldValidator(Permission permission) {
104 this(Stapler.getCurrentRequest(),Stapler.getCurrentResponse(),permission);
105 }
106
107 /**
108 * @deprecated
109 * Use {@link #FormFieldValidator(AccessControlled,Permission)} and remove {@link StaplerRequest} and {@link StaplerResponse}
110 * from your "doCheck..." method parameter
111 */
112 protected FormFieldValidator(StaplerRequest request, StaplerResponse response, AccessControlled subject, Permission permission) {
113 this.request = request;
114 this.response = response;
115 this.subject = subject;
116 this.permission = permission;
117 }
118
119 protected FormFieldValidator(AccessControlled subject, Permission permission) {
120 this(Stapler.getCurrentRequest(),Stapler.getCurrentResponse(),subject,permission);
121 }
122
123 /**
124 * Runs the validation code.
125 */
126 public final void process() throws IOException, ServletException {
127 if(permission!=null)
128 try {
129 if(subject==null)
130 throw new AccessDeniedException("No subject");
131 subject.checkPermission(permission);
132 } catch (AccessDeniedException e) {
133 // if the user has hudson-wisde admin permission, all checks are allowed
134 // this is to protect Hudson administrator from broken ACL/SecurityRealm implementation/configuration.
135 if(!Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER))
136 throw e;
137 }
138
139 check();
140 }
141
142 protected abstract void check() throws IOException, ServletException;
143
144 /**
145 * Gets the parameter as a file.
146 */
147 protected final File getFileParameter(String paramName) {
148 return new File(Util.fixNull(request.getParameter(paramName)));
149 }
150
151 /**
152 * Sends out an HTML fragment that indicates a success.
153 */
154 public void ok() throws IOException, ServletException {
155 respond("<div/>");
156 }
157
158 /**
159 * Sends out an arbitrary HTML fragment.
160 */
161 public void respond(String html) throws IOException, ServletException {
162 response.setContentType("text/html");
163 response.getWriter().print(html);
164 }
165
166 /**
167 * Sends out a string error message that indicates an error.
168 *
169 * @param message
170 * Human readable message to be sent. <tt>error(null)</tt>
171 * can be used as <tt>ok()</tt>.
172 */
173 public void error(String message) throws IOException, ServletException {
174 errorWithMarkup(message==null?null:Util.escape(message));
175 }
176
177 public void warning(String message) throws IOException, ServletException {
178 warningWithMarkup(message==null?null:Util.escape(message));
179 }
180
181 public void ok(String message) throws IOException, ServletException {
182 okWithMarkup(message==null?null:Util.escape(message));
183 }
184
185 /**
186 * Sends out a string error message that indicates an error,
187 * by formatting it with {@link String#format(String, Object[])}
188 */
189 public void error(String format, Object... args) throws IOException, ServletException {
190 error(String.format(format,args));
191 }
192
193 public void warning(String format, Object... args) throws IOException, ServletException {
194 warning(String.format(format,args));
195 }
196
197 public void ok(String format, Object... args) throws IOException, ServletException {
198 ok(String.format(format,args));
199 }
200
201 /**
202 * Sends out an HTML fragment that indicates an error.
203 *
204 * <p>
205 * This method must be used with care to avoid cross-site scripting
206 * attack.
207 *
208 * @param message
209 * Human readable message to be sent. <tt>error(null)</tt>
210 * can be used as <tt>ok()</tt>.
211 */
212 public void errorWithMarkup(String message) throws IOException, ServletException {
213 _errorWithMarkup(message,"error");
214 }
215
216 public void warningWithMarkup(String message) throws IOException, ServletException {
217 _errorWithMarkup(message,"warning");
218 }
219
220 public void okWithMarkup(String message) throws IOException, ServletException {
221 _errorWithMarkup(message,"ok");
222 }
223
224 private void _errorWithMarkup(String message, String cssClass) throws IOException, ServletException {
225 if(message==null) {
226 ok();
227 } else {
228 response.setContentType("text/html;charset=UTF-8");
229 // 1x16 spacer needed for IE since it doesn't support min-height
230 response.getWriter().print("<div class="+ cssClass +"><img src='"+
231 request.getContextPath()+ Jenkins.RESOURCE_PATH+"/images/none.gif' height=16 width=1>"+
232 message+"</div>");
233 }
234 }
235
236 /**
237 * Convenient base class for checking the validity of URLs
238 *
239 * @deprecated as of 1.294
240 * Use {@link FormValidation.URLCheck}
241 */
242 public static abstract class URLCheck extends FormFieldValidator {
243
244 public URLCheck(StaplerRequest request, StaplerResponse response) {
245 // can be used to check the existence of any file in file system
246 // or other HTTP URLs inside firewall, so limit this to the admin.
247 super(request, response, true);
248 }
249
250 /**
251 * Opens the given URL and reads text content from it.
252 * This method honors Content-type header.
253 */
254 protected BufferedReader open(URL url) throws IOException {
255 // use HTTP content type to find out the charset.
256 URLConnection con = ProxyConfiguration.open(url);
257 if (con == null) { // XXX is this even permitted by URL.openConnection?
258 throw new IOException(url.toExternalForm());
259 }
260 return new BufferedReader(
261 new InputStreamReader(con.getInputStream(),getCharset(con)));
262 }
263
264 /**
265 * Finds the string literal from the given reader.
266 * @return
267 * true if found, false otherwise.
268 */
269 protected boolean findText(BufferedReader in, String literal) throws IOException {
270 String line;
271 while((line=in.readLine())!=null)
272 if(line.indexOf(literal)!=-1)
273 return true;
274 return false;
275 }
276
277 /**
278 * Calls the {@link #error(String)} method with a reasonable error message.
279 * Use this method when the {@link #open(URL)} or {@link #findText(BufferedReader, String)} fails.
280 *
281 * @param url
282 * Pass in the URL that was connected. Used for error diagnosis.
283 */
284 protected void handleIOException(String url, IOException e) throws IOException, ServletException {
285 // any invalid URL comes here
286 if(e.getMessage().equals(url))
287 // Sun JRE (and probably others too) often return just the URL in the error.
288 error("Unable to connect "+url);
289 else
290 error(e.getMessage());
291 }
292
293 /**
294 * Figures out the charset from the content-type header.
295 */
296 private String getCharset(URLConnection con) {
297 for( String t : con.getContentType().split(";") ) {
298 t = t.trim().toLowerCase(Locale.ENGLISH);
299 if(t.startsWith("charset="))
300 return t.substring(8);
301 }
302 // couldn't find it. HTML spec says default is US-ASCII,
303 // but UTF-8 is a better choice since
304 // (1) it's compatible with US-ASCII
305 // (2) a well-written web applications tend to use UTF-8
306 return "UTF-8";
307 }
308 }
309
310 /**
311 * Checks if the given value is an URL to some Hudson's top page.
312 * @since 1.192
313 */
314 public static class HudsonURL extends URLCheck {
315 public HudsonURL(StaplerRequest request, StaplerResponse response) {
316 super(request, response);
317 }
318
319 protected void check() throws IOException, ServletException {
320 String value = fixEmpty(request.getParameter("value"));
321 if(value==null) {// nothing entered yet
322 ok();
323 return;
324 }
325
326 if(!value.endsWith("/")) value+='/';
327
328 try {
329 URL url = new URL(value);
330 HttpURLConnection con = (HttpURLConnection)url.openConnection();
331 con.connect();
332 if(con.getResponseCode()!=200
333 || con.getHeaderField("X-Hudson")==null) {
334 error(value+" is not Hudson ("+con.getResponseMessage()+")");
335 return;
336 }
337
338 ok();
339 } catch (IOException e) {
340 handleIOException(value,e);
341 }
342 }
343 }
344
345 /**
346 * Checks the file mask (specified in the 'value' query parameter) against
347 * the current workspace.
348 * @since 1.90.
349 * @deprecated as of 1.294. Use {@link FilePath#validateFileMask(String, boolean)}
350 */
351 public static class WorkspaceFileMask extends FormFieldValidator {
352 private final boolean errorIfNotExist;
353
354 public WorkspaceFileMask(StaplerRequest request, StaplerResponse response) {
355 this(request, response, true);
356 }
357
358 public WorkspaceFileMask(StaplerRequest request, StaplerResponse response, boolean errorIfNotExist) {
359 // Require CONFIGURE permission on the job
360 super(request, response, request.findAncestorObject(AbstractProject.class), Item.CONFIGURE);
361 this.errorIfNotExist = errorIfNotExist;
362 }
363
364 protected void check() throws IOException, ServletException {
365 String value = fixEmpty(request.getParameter("value"));
366 AbstractProject<?,?> p = (AbstractProject<?,?>)subject;
367
368 if(value==null || p==null) {
369 ok(); // none entered yet, or something is seriously wrong
370 return;
371 }
372
373 try {
374 FilePath ws = getBaseDirectory(p);
375
376 if(ws==null || !ws.exists()) {// no workspace. can't check
377 ok();
378 return;
379 }
380
381 String msg = ws.validateAntFileMask(value, 10000);
382 if(errorIfNotExist) error(msg);
383 else warning(msg);
384 } catch (InterruptedException e) {
385 ok(Messages.FormFieldValidator_did_not_manage_to_validate_may_be_too_sl(value));
386 }
387 }
388
389 /**
390 * The base directory from which the path name is resolved.
391 */
392 protected FilePath getBaseDirectory(AbstractProject<?,?> p) {
393 return p.getSomeWorkspace();
394 }
395 }
396
397 /**
398 * Checks a valid directory name (specified in the 'value' query parameter) against
399 * the current workspace.
400 * @since 1.116
401 * @deprecated as of 1.294. Use {@link FilePath#validateRelativeDirectory(String, boolean)}
402 * (see javadoc plugin for the example)
403 */
404 public static class WorkspaceDirectory extends WorkspaceFilePath {
405 public WorkspaceDirectory(StaplerRequest request, StaplerResponse response, boolean errorIfNotExist) {
406 super(request, response, errorIfNotExist, false);
407 }
408
409 public WorkspaceDirectory(StaplerRequest request, StaplerResponse response) {
410 this(request, response, true);
411 }
412 }
413
414 /**
415 * Checks a valid file name or directory (specified in the 'value' query parameter) against
416 * the current workspace.
417 * @since 1.160
418 * @deprecated as of 1.294. Use {@link FilePath#validateRelativePath(String, boolean, boolean)}
419 */
420 public static class WorkspaceFilePath extends FormFieldValidator {
421 private final boolean errorIfNotExist;
422 private final boolean expectingFile;
423
424 public WorkspaceFilePath(StaplerRequest request, StaplerResponse response, boolean errorIfNotExist, boolean expectingFile) {
425 // Require CONFIGURE permission on this job
426 super(request, response, request.findAncestorObject(AbstractProject.class), Item.CONFIGURE);
427 this.errorIfNotExist = errorIfNotExist;
428 this.expectingFile = expectingFile;
429 }
430
431 protected void check() throws IOException, ServletException {
432 String value = fixEmpty(request.getParameter("value"));
433 AbstractProject<?,?> p = (AbstractProject<?,?>)subject;
434
435 if(value==null || p==null) {
436 ok(); // none entered yet, or something is seriously wrong
437 return;
438 }
439
440 if(value.contains("*")) {
441 // a common mistake is to use wildcard
442 error("Wildcard is not allowed here");
443 return;
444 }
445
446 try {
447 FilePath ws = getBaseDirectory(p);
448
449 if(ws==null) {// can't check
450 ok();
451 return;
452 }
453
454 if(!ws.exists()) {// no workspace. can't check
455 ok();
456 return;
457 }
458
459 if(ws.child(value).exists()) {
460 if (expectingFile) {
461 if(!ws.child(value).isDirectory())
462 ok();
463 else
464 error(value+" is not a file");
465 } else {
466 if(ws.child(value).isDirectory())
467 ok();
468 else
469 error(value+" is not a directory");
470 }
471 } else {
472 String msg = "No such "+(expectingFile?"file":"directory")+": " + value;
473 if(errorIfNotExist) error(msg);
474 else warning(msg);
475 }
476 } catch (InterruptedException e) {
477 ok(); // coundn't check
478 }
479 }
480
481 /**
482 * The base directory from which the path name is resolved.
483 */
484 protected FilePath getBaseDirectory(AbstractProject<?,?> p) {
485 return p.getSomeWorkspace();
486 }
487 }
488
489 /**
490 * Checks a valid executable binary (specified in the 'value' query parameter).
491 * It has to be either given as a full path to the executable, or else
492 * it will be searched in PATH.
493 *
494 * <p>
495 * This file also handles ".exe" omission in Windows --- I thought Windows
496 * has actually more generic mechanism for the executable extension omission,
497 * so perhaps this needs to be extended to handle that correctly. More info
498 * needed.
499 *
500 * @since 1.124
501 * @deprecated as of 1.294. Use {@link FormValidation#validateExecutable(String)}
502 */
503 public static class Executable extends FormFieldValidator {
504
505 public Executable(StaplerRequest request, StaplerResponse response) {
506 // Require admin permission
507 super(request, response, true);
508 }
509
510 protected void check() throws IOException, ServletException {
511 String exe = fixEmpty(request.getParameter("value"));
512 if(exe==null) {
513 ok(); // nothing entered yet
514 return;
515 }
516
517 if(exe.indexOf(File.separatorChar)>=0) {
518 // this is full path
519 File f = new File(exe);
520 if(f.exists()) {
521 checkExecutable(f);
522 return;
523 }
524
525 File fexe = new File(exe+".exe");
526 if(fexe.exists()) {
527 checkExecutable(fexe);
528 return;
529 }
530
531 error("There's no such file: "+exe);
532 } else {
533 // look in PATH
534 String path = EnvVars.masterEnvVars.get("PATH");
535 String tokenizedPath = "";
536 String delimiter = null;
537 if(path!=null) {
538 for (String _dir : Util.tokenize(path.replace("\\", "\\\\"),File.pathSeparator)) {
539 if (delimiter == null) {
540 delimiter = ", ";
541 }
542 else {
543 tokenizedPath += delimiter;
544 }
545
546 tokenizedPath += _dir.replace('\\', '/');
547
548 File dir = new File(_dir);
549
550 File f = new File(dir,exe);
551 if(f.exists()) {
552 checkExecutable(f);
553 return;
554 }
555
556 File fexe = new File(dir,exe+".exe");
557 if(fexe.exists()) {
558 checkExecutable(fexe);
559 return;
560 }
561 }
562
563 tokenizedPath += ".";
564 }
565 else {
566 tokenizedPath = "unavailable.";
567 }
568
569 // didn't find it
570 error("There's no such executable "+exe+" in PATH: "+tokenizedPath);
571 }
572 }
573
574 /**
575 * Provides an opportunity for derived classes to do additional checks on the executable.
576 */
577 protected void checkExecutable(File exe) throws IOException, ServletException {
578 ok();
579 }
580 }
581
582 /**
583 * Verifies that the 'value' parameter is correct base64 encoded text.
584 *
585 * @since 1.257
586 * @deprecated as of 1.305
587 * Use {@link FormValidation#validateBase64(String, boolean, boolean, String)} instead.
588 */
589 public static class Base64 extends FormFieldValidator {
590 private final boolean allowWhitespace;
591 private final boolean allowEmpty;
592 private final String errorMessage;
593
594 public Base64(StaplerRequest request, StaplerResponse response, boolean allowWhitespace, boolean allowEmpty, String errorMessage) {
595 super(request, response, false);
596 this.allowWhitespace = allowWhitespace;
597 this.allowEmpty = allowEmpty;
598 this.errorMessage = errorMessage;
599 }
600
601 protected void check() throws IOException, ServletException {
602 try {
603 String v = request.getParameter("value");
604 if(!allowWhitespace) {
605 if(v.indexOf(' ')>=0 || v.indexOf('\n')>=0) {
606 fail();
607 return;
608 }
609 }
610 v=v.trim();
611 if(!allowEmpty && v.length()==0) {
612 fail();
613 return;
614 }
615
616 com.trilead.ssh2.crypto.Base64.decode(v.toCharArray());
617 ok();
618 } catch (IOException e) {
619 fail();
620 }
621 }
622
623 protected void fail() throws IOException, ServletException {
624 error(errorMessage);
625 }
626 }
627
628 /**
629 * Verifies that the 'value' parameter is an integer >= 0.
630 *
631 * @since 1.282
632 * @deprecated as of 1.294
633 * Use {@link FormValidation#validateNonNegativeInteger(String)}
634 */
635 public static class NonNegativeInteger extends FormFieldValidator {
636 public NonNegativeInteger() {
637 super(null);
638 }
639
640 protected void check() throws IOException, ServletException {
641 try {
642 String value = request.getParameter("value");
643 if(Integer.parseInt(value)<0)
644 error(hudson.model.Messages.Hudson_NotAPositiveNumber());
645 else
646 ok();
647 } catch (NumberFormatException e) {
648 error(hudson.model.Messages.Hudson_NotANumber());
649 }
650 }
651 }
652 }
653