Index: java/hudson/util/FormFieldValidator.java
===================================================================
--- java/hudson/util/FormFieldValidator.java (revision 13718)
+++ java/hudson/util/FormFieldValidator.java (working copy)
@@ -6,6 +6,7 @@
import hudson.Util;
import hudson.model.AbstractProject;
import hudson.model.Hudson;
+import hudson.model.Item;
import hudson.security.Permission;
import hudson.security.AccessControlled;
@@ -57,9 +58,34 @@
}
protected FormFieldValidator(StaplerRequest request, StaplerResponse response, Permission permission) {
- this(request,response,Hudson.getInstance(),permission);
+ this(request,response,permission,false);
}
+ /**
+ * @param jobContext
+ * If false then checks given permission against Hudson instance.
+ * If true then request.getRestOfPath() is checked for the full name
+ * of job to check permission against. If null or invalid, then checks
+ * for admin permission instead (given Permission not used).
+ */
+ protected FormFieldValidator(StaplerRequest request, StaplerResponse response, Permission permission, boolean jobContext) {
+ this.request = request;
+ this.response = response;
+ if (!jobContext) {
+ this.subject = Hudson.getInstance();
+ this.permission = permission;
+ } else {
+ AbstractProject,?> project = getProjectFromURL();
+ if (project != null) {
+ this.subject = project;
+ this.permission = permission;
+ } else {
+ this.subject = Hudson.getInstance();
+ this.permission = CHECK;
+ }
+ }
+ }
+
protected FormFieldValidator(StaplerRequest request, StaplerResponse response, AccessControlled subject, Permission permission) {
this.request = request;
this.response = response;
@@ -80,6 +106,14 @@
protected abstract void check() throws IOException, ServletException;
/**
+ * Get project context from the remainder of this URL (request.getRestOfPath()).
+ */
+ protected AbstractProject,?> getProjectFromURL() {
+ String fullName = request.getRestOfPath();
+ return fullName.length() > 0 ? Hudson.getInstance().getItemByFullName(fullName,AbstractProject.class) : null;
+ }
+
+ /**
* Gets the parameter as a file.
*/
protected final File getFileParameter(String paramName) {
@@ -271,13 +305,14 @@
}
public WorkspaceFileMask(StaplerRequest request, StaplerResponse response, boolean errorIfNotExist) {
- super(request, response, false);
+ // Require CONFIGURE permission on this job
+ super(request, response, Item.CONFIGURE, true);
this.errorIfNotExist = errorIfNotExist;
}
protected void check() throws IOException, ServletException {
String value = fixEmpty(request.getParameter("value"));
- AbstractProject,?> p = Hudson.getInstance().getItemByFullName(request.getParameter("job"),AbstractProject.class);
+ AbstractProject,?> p = getProjectFromURL();
if(value==null || p==null) {
ok(); // none entered yet, or something is seriously wrong
@@ -333,14 +368,15 @@
private final boolean expectingFile;
public WorkspaceFilePath(StaplerRequest request, StaplerResponse response, boolean errorIfNotExist, boolean expectingFile) {
- super(request, response, false);
+ // Require CONFIGURE permission on this job
+ super(request, response, Item.CONFIGURE, true);
this.errorIfNotExist = errorIfNotExist;
this.expectingFile = expectingFile;
}
protected void check() throws IOException, ServletException {
String value = fixEmpty(request.getParameter("value"));
- AbstractProject, ?> p = getProject();
+ AbstractProject, ?> p = getProjectFromURL();
if(value==null || p==null) {
ok(); // none entered yet, or something is seriously wrong
@@ -394,10 +430,6 @@
protected FilePath getBaseDirectory(AbstractProject,?> p) {
return p.getWorkspace();
}
-
- protected AbstractProject,?> getProject() {
- return Hudson.getInstance().getItemByFullName(request.getParameter("job"),AbstractProject.class);
- }
}
/**
@@ -416,6 +448,7 @@
public static class Executable extends FormFieldValidator {
public Executable(StaplerRequest request, StaplerResponse response) {
+ // Require admin permission
super(request, response, true);
}
Index: java/hudson/model/Hudson.java
===================================================================
--- java/hudson/model/Hudson.java (revision 13718)
+++ java/hudson/model/Hudson.java (working copy)
@@ -2270,6 +2270,7 @@
*/
public void doCheckLocalFSRoot( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
// this can be used to check the existence of a file on the server, so needs to be protected
+ // WorkspaceDirectory checks CONFIGURE permission on job specified in req.getRestOfPath()
new FormFieldValidator.WorkspaceDirectory(req,rsp,true).process();
}
@@ -2326,7 +2327,7 @@
public void doItemExistsCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
// this method can be used to check if a file exists anywhere in the file system,
// so it should be protected.
- new FormFieldValidator(req,rsp,true) {
+ new FormFieldValidator(req,rsp,Item.CREATE) {
protected void check() throws IOException, ServletException {
String job = fixEmpty(request.getParameter("value"));
if(job==null) {
Index: java/hudson/scm/SubversionSCM.java
===================================================================
--- java/hudson/scm/SubversionSCM.java (revision 13718)
+++ java/hudson/scm/SubversionSCM.java (working copy)
@@ -1258,8 +1258,8 @@
* validate the value for a remote (repository) location.
*/
public void doSvnRemoteLocationCheck(final StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
- // this can be used to hit any accessible URL, so limit that to admins
- new FormFieldValidator(req, rsp, true) {
+ // false==No permisison needed for basic check
+ new FormFieldValidator(req, rsp, false) {
protected void check() throws IOException, ServletException {
// syntax check first
String url = Util.nullify(request.getParameter("value"));
@@ -1277,8 +1277,10 @@
return;
}
- // test the connection
- try {
+ // Test the connection only if we have admin permission
+ if (!Hudson.getInstance().hasPermission(Hudson.ADMINISTER)) {
+ ok();
+ } else try {
SVNURL repoURL = SVNURL.parseURIDecoded(url);
if (checkRepositoryPath(repoURL)==SVNNodeKind.NONE) {
SVNRepository repository = null;
@@ -1370,6 +1372,7 @@
* validate the value for a local location (local checkout directory).
*/
public void doSvnLocalLocationCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+ // false==No permission needed for this syntax check
new FormFieldValidator(req, rsp, false) {
protected void check() throws IOException, ServletException {
String v = Util.nullify(request.getParameter("value"));
Index: java/hudson/scm/browsers/FishEyeSVN.java
===================================================================
--- java/hudson/scm/browsers/FishEyeSVN.java (revision 13718)
+++ java/hudson/scm/browsers/FishEyeSVN.java (working copy)
@@ -2,6 +2,7 @@
import static hudson.Util.fixEmpty;
import hudson.model.Descriptor;
+import hudson.model.Hudson;
import hudson.scm.RepositoryBrowser;
import hudson.scm.SubversionChangeLogSet.LogEntry;
import hudson.scm.SubversionChangeLogSet.Path;
@@ -116,7 +117,9 @@
* Performs on-the-fly validation of the URL.
*/
public void doCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
- new FormFieldValidator.URLCheck(req,rsp) {
+ // false==No permission needed for basic check
+ new FormFieldValidator(req,rsp,false) {
+ @Override
protected void check() throws IOException, ServletException {
String value = fixEmpty(request.getParameter("value"));
if(value==null) {// nothing entered yet
@@ -130,14 +133,25 @@
return;
}
- try {
- if(findText(open(new URL(value)),"FishEye")) {
- ok();
- } else {
- error("This is a valid URL but it doesn't look like FishEye");
- }
- } catch (IOException e) {
- handleIOException(value,e);
+ // Connect to URL and check content only if we have admin permission
+ if (Hudson.getInstance().hasPermission(Hudson.ADMINISTER)) {
+ final String finalValue = value;
+ new FormFieldValidator.URLCheck(request,response) {
+ @Override
+ protected void check() throws IOException, ServletException {
+ try {
+ if(findText(open(new URL(finalValue)),"FishEye")) {
+ ok();
+ } else {
+ error("This is a valid URL but it doesn't look like FishEye");
+ }
+ } catch (IOException e) {
+ handleIOException(finalValue,e);
+ }
+ }
+ }.process();
+ } else {
+ ok();
}
}
}.process();
Index: java/hudson/scm/browsers/FishEyeCVS.java
===================================================================
--- java/hudson/scm/browsers/FishEyeCVS.java (revision 13718)
+++ java/hudson/scm/browsers/FishEyeCVS.java (working copy)
@@ -2,6 +2,7 @@
import hudson.Util;
import hudson.model.Descriptor;
+import hudson.model.Hudson;
import hudson.scm.CVSChangeLogSet;
import hudson.scm.CVSChangeLogSet.File;
import hudson.scm.CVSChangeLogSet.Revision;
@@ -70,7 +71,8 @@
}
public void doCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
- new FormFieldValidator.URLCheck(req,rsp) {
+ // false==No permission needed for basic check
+ new FormFieldValidator(req,rsp,false) {
@Override
protected void check() throws IOException, ServletException {
String value = Util.fixEmpty(request.getParameter("value"));
@@ -85,14 +87,25 @@
errorWithMarkup("The URL should end like .../browse/foobar/");
return;
}
- try {
- if (findText(open(new URL(value)), "FishEye")) {
- ok();
- } else {
- error("This is a valid URL but it doesn't look like FishEye");
- }
- } catch (IOException e) {
- handleIOException(value, e);
+ // Connect to URL and check content only if we have admin permission
+ if (Hudson.getInstance().hasPermission(Hudson.ADMINISTER)) {
+ final String finalValue = value;
+ new FormFieldValidator.URLCheck(request,response) {
+ @Override
+ protected void check() throws IOException, ServletException {
+ try {
+ if (findText(open(new URL(finalValue)), "FishEye")) {
+ ok();
+ } else {
+ error("This is a valid URL but it doesn't look like FishEye");
+ }
+ } catch (IOException e) {
+ handleIOException(finalValue, e);
+ }
+ }
+ }.process();
+ } else {
+ ok();
}
}
}.process();
Index: java/hudson/scm/browsers/Sventon.java
===================================================================
--- java/hudson/scm/browsers/Sventon.java (revision 13718)
+++ java/hudson/scm/browsers/Sventon.java (working copy)
@@ -118,6 +118,7 @@
* Performs on-the-fly validation of the URL.
*/
public void doCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+ // URLCheck requires Admin permission
new FormFieldValidator.URLCheck(req,rsp) {
protected void check() throws IOException, ServletException {
String value = fixEmpty(request.getParameter("value"));
Index: java/hudson/tasks/test/AggregatedTestResultPublisher.java
===================================================================
--- java/hudson/tasks/test/AggregatedTestResultPublisher.java (revision 13718)
+++ java/hudson/tasks/test/AggregatedTestResultPublisher.java (working copy)
@@ -7,6 +7,7 @@
import hudson.model.BuildListener;
import hudson.model.Fingerprint.RangeSet;
import hudson.model.Hudson;
+import hudson.model.Item;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.TaskListener;
@@ -226,7 +227,8 @@
}
public void doCheck(StaplerRequest req, StaplerResponse rsp, @QueryParameter final String value) throws IOException, ServletException {
- new FormFieldValidator(req,rsp,false) {
+ // Require CONFIGURE permission on this project
+ new FormFieldValidator(req,rsp,Item.CONFIGURE,true) {
protected void check() throws IOException, ServletException {
for (String name : Util.tokenize(value, ",")) {
name = name.trim();
Index: java/hudson/tasks/Shell.java
===================================================================
--- java/hudson/tasks/Shell.java (revision 13718)
+++ java/hudson/tasks/Shell.java (working copy)
@@ -127,6 +127,7 @@
* Check the existence of sh in the given location.
*/
public void doCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+ // Executable requires admin permission
new FormFieldValidator.Executable(req,rsp).process();
}
}
Index: java/hudson/tasks/junit/JUnitResultArchiver.java
===================================================================
--- java/hudson/tasks/junit/JUnitResultArchiver.java (revision 13718)
+++ java/hudson/tasks/junit/JUnitResultArchiver.java (working copy)
@@ -132,6 +132,7 @@
* Performs on-the-fly validation on the file mask wildcard.
*/
public void doCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+ // WorkspaceFileMask requires CONFIGURE permission on this project
new FormFieldValidator.WorkspaceFileMask(req,rsp).process();
}
Index: java/hudson/tasks/Fingerprinter.java
===================================================================
--- java/hudson/tasks/Fingerprinter.java (revision 13718)
+++ java/hudson/tasks/Fingerprinter.java (working copy)
@@ -195,6 +195,7 @@
* Performs on-the-fly validation on the file mask wildcard.
*/
public void doCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+ // WorkspaceFileMask requires CONFIGURE permission on this project
new FormFieldValidator.WorkspaceFileMask(req,rsp).process();
}
Index: java/hudson/tasks/ArtifactArchiver.java
===================================================================
--- java/hudson/tasks/ArtifactArchiver.java (revision 13718)
+++ java/hudson/tasks/ArtifactArchiver.java (working copy)
@@ -142,6 +142,7 @@
* Performs on-the-fly validation on the file mask wildcard.
*/
public void doCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+ // WorkspaceFileMask requires CONFIGURE permission on this project
new FormFieldValidator.WorkspaceFileMask(req,rsp).process();
}
Index: java/hudson/tasks/BuildTrigger.java
===================================================================
--- java/hudson/tasks/BuildTrigger.java (revision 13718)
+++ java/hudson/tasks/BuildTrigger.java (working copy)
@@ -272,7 +272,8 @@
* Form validation method.
*/
public void doCheck( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
- new FormFieldValidator(req,rsp,true) {
+ // Require CONFIGURE permission on this project
+ new FormFieldValidator(req,rsp,Item.CONFIGURE,true) {
protected void check() throws IOException, ServletException {
String list = request.getParameter("value");
Index: java/hudson/tasks/JavadocArchiver.java
===================================================================
--- java/hudson/tasks/JavadocArchiver.java (revision 13718)
+++ java/hudson/tasks/JavadocArchiver.java (working copy)
@@ -187,6 +187,7 @@
* Performs on-the-fly validation on the file mask wildcard.
*/
public void doCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+ // WorkspaceDirectory requires CONFIGURE permission on this project
new FormFieldValidator.WorkspaceDirectory(req,rsp).process();
}
Index: java/hudson/triggers/TimerTrigger.java
===================================================================
--- java/hudson/triggers/TimerTrigger.java (revision 13718)
+++ java/hudson/triggers/TimerTrigger.java (working copy)
@@ -59,7 +59,9 @@
* Performs syntax check.
*/
public void doCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
- new FormFieldValidator(req,rsp,true) {
+ // false==No permission needed for this syntax check
+ new FormFieldValidator(req,rsp,false) {
+ @Override
protected void check() throws IOException, ServletException {
try {
String msg = CronTabList.create(fixNull(request.getParameter("value"))).checkSanity();
Index: java/hudson/Functions.java
===================================================================
--- java/hudson/Functions.java (revision 13718)
+++ java/hudson/Functions.java (working copy)
@@ -445,6 +445,10 @@
return Util.xmlEscape(s);
}
+ public static String jsEscape(String s) {
+ return Util.jsEscape(s);
+ }
+
public static void checkPermission(Permission permission) throws IOException, ServletException {
checkPermission(Hudson.getInstance(),permission);
}
Index: java/hudson/Util.java
===================================================================
--- java/hudson/Util.java (revision 13718)
+++ java/hudson/Util.java (working copy)
@@ -148,7 +148,7 @@
if(!logfile.exists())
return "";
- StringBuffer str = new StringBuffer((int)logfile.length());
+ StringBuilder str = new StringBuilder((int)logfile.length());
BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(logfile),charset));
char[] buf = new char[1024];
@@ -433,7 +433,7 @@
}
public static String toHexString(byte[] data, int start, int len) {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
for( int i=0; i='a') ch = (char)(ch-'a'+'A');
Index: resources/hudson/scm/browsers/Sventon/config.jelly
===================================================================
--- resources/hudson/scm/browsers/Sventon/config.jelly (revision 13718)
+++ resources/hudson/scm/browsers/Sventon/config.jelly (working copy)
@@ -1,9 +1,14 @@
-
+
+
+
+
+
+
+
-
\ No newline at end of file
+
Index: resources/hudson/tasks/test/AggregatedTestResultPublisher/config.jelly
===================================================================
--- resources/hudson/tasks/test/AggregatedTestResultPublisher/config.jelly (revision 13718)
+++ resources/hudson/tasks/test/AggregatedTestResultPublisher/config.jelly (working copy)
@@ -8,9 +8,9 @@
+ checkUrl="'${rootURL}/publisher/AggregatedTestResultPublisher/check/${h.jsEscape(it.fullName)}?value='+escape(this.value)"/>
-
\ No newline at end of file
+
Index: resources/hudson/tasks/ArtifactArchiver/config.jelly
===================================================================
--- resources/hudson/tasks/ArtifactArchiver/config.jelly (revision 13718)
+++ resources/hudson/tasks/ArtifactArchiver/config.jelly (working copy)
@@ -1,7 +1,7 @@
+ checkUrl="'${rootURL}/publisher/ArtifactArchiver/check/${h.jsEscape(it.fullName)}?value='+escape(this.value)" />
@@ -12,4 +12,4 @@
-
\ No newline at end of file
+
Index: resources/hudson/tasks/BuildTrigger/config.jelly
===================================================================
--- resources/hudson/tasks/BuildTrigger/config.jelly (revision 13718)
+++ resources/hudson/tasks/BuildTrigger/config.jelly (working copy)
@@ -1,7 +1,7 @@
+ checkUrl="'${rootURL}/publisher/BuildTrigger/check/${h.jsEscape(it.fullName)}?value='+escape(this.value)"/>
@@ -9,4 +9,4 @@
-
\ No newline at end of file
+
Index: resources/hudson/tasks/junit/JUnitResultArchiver/config.jelly
===================================================================
--- resources/hudson/tasks/junit/JUnitResultArchiver/config.jelly (revision 13718)
+++ resources/hudson/tasks/junit/JUnitResultArchiver/config.jelly (working copy)
@@ -2,6 +2,6 @@
+ checkUrl="'${rootURL}/publisher/JUnitResultArchiver/check/${h.jsEscape(it.fullName)}?value='+escape(this.value)"/>
-
\ No newline at end of file
+
Index: resources/hudson/tasks/JavadocArchiver/config.jelly
===================================================================
--- resources/hudson/tasks/JavadocArchiver/config.jelly (revision 13718)
+++ resources/hudson/tasks/JavadocArchiver/config.jelly (working copy)
@@ -2,10 +2,10 @@
+ checkUrl="'${rootURL}/publisher/JavadocArchiver/check/${h.jsEscape(it.fullName)}?value='+escape(this.value)"/>
-
\ No newline at end of file
+
Index: resources/hudson/tasks/Fingerprinter/config.jelly
===================================================================
--- resources/hudson/tasks/Fingerprinter/config.jelly (revision 13718)
+++ resources/hudson/tasks/Fingerprinter/config.jelly (working copy)
@@ -2,7 +2,7 @@
+ checkUrl="'${rootURL}/publisher/Fingerprinter/check/${h.jsEscape(it.fullName)}?value='+escape(this.value)" />
@@ -12,4 +12,4 @@
-
\ No newline at end of file
+
Index: resources/hudson/triggers/TimerTrigger/config.jelly
===================================================================
--- resources/hudson/triggers/TimerTrigger/config.jelly (revision 13718)
+++ resources/hudson/triggers/TimerTrigger/config.jelly (working copy)
@@ -2,4 +2,4 @@
-
\ No newline at end of file
+
Index: resources/hudson/triggers/SCMTrigger/config.jelly
===================================================================
--- resources/hudson/triggers/SCMTrigger/config.jelly (revision 13718)
+++ resources/hudson/triggers/SCMTrigger/config.jelly (working copy)
@@ -2,4 +2,4 @@
-
\ No newline at end of file
+
Index: resources/lib/hudson/project/config-upstream-pseudo-trigger.jelly
===================================================================
--- resources/lib/hudson/project/config-upstream-pseudo-trigger.jelly (revision 13718)
+++ resources/lib/hudson/project/config-upstream-pseudo-trigger.jelly (working copy)
@@ -13,8 +13,8 @@
-
\ No newline at end of file
+