提交 f21fa55f 编写于 作者: K kohsuke

Merged revisions 8523-8525,8545-8556,8793,8803-8806,8858,9027-9028 via svnmerge from

https://www.dev.java.net/svn/hudson/branches/tom

........
  r8523 | huybrechts | 2008-04-11 13:41:11 -0700 (Fri, 11 Apr 2008) | 1 line
  
  profile to build against current snapshot of hudson-core
........
  r8524 | huybrechts | 2008-04-11 14:42:58 -0700 (Fri, 11 Apr 2008) | 1 line
  
  [#710] project option to automatically delete the svn wc if it is locked
........
  r8525 | huybrechts | 2008-04-11 14:53:59 -0700 (Fri, 11 Apr 2008) | 1 line
  
  [#710] project option to automatically delete the svn wc if it is locked
........
  r8545 | huybrechts | 2008-04-12 04:17:46 -0700 (Sat, 12 Apr 2008) | 1 line
  
  profile to build against current snapshot of hudson-core
........
  r8546 | huybrechts | 2008-04-12 04:19:26 -0700 (Sat, 12 Apr 2008) | 1 line
  
  deleting IDE-specific files
........
  r8547 | huybrechts | 2008-04-12 06:31:32 -0700 (Sat, 12 Apr 2008) | 1 line
  
  added ignores
........
  r8548 | huybrechts | 2008-04-12 06:42:49 -0700 (Sat, 12 Apr 2008) | 4 lines
  
  Issue 1158
  - extended AuthorizationStrategy to provide ACLs for different types of objects
  - changed several object types to use these methods
  - changed jelly to check permissions (instead of using isAdmin check)
........
  r8549 | huybrechts | 2008-04-12 06:44:26 -0700 (Sat, 12 Apr 2008) | 1 line
  
  Issue 1110: use svn revision number in project-changes.jelly
........
  r8550 | huybrechts | 2008-04-12 06:46:18 -0700 (Sat, 12 Apr 2008) | 1 line
  
  Adding a 'My Projects' view which shows only projects the user has permission for
........
  r8551 | huybrechts | 2008-04-12 06:47:57 -0700 (Sat, 12 Apr 2008) | 1 line
  
  adding a user name resolver, like the MailAddressResolver
........
  r8552 | huybrechts | 2008-04-12 06:49:27 -0700 (Sat, 12 Apr 2008) | 1 line
  
  Adding jdom and cglib to the war, as a workaround for classloading issues
........
  r8553 | huybrechts | 2008-04-12 08:01:58 -0700 (Sat, 12 Apr 2008) | 1 line
  
  SFEE integration improvements, including links to project based security
........
  r8554 | huybrechts | 2008-04-12 08:27:17 -0700 (Sat, 12 Apr 2008) | 1 line
  
  wsdl for SFEE webservices
........
  r8555 | huybrechts | 2008-04-12 08:31:18 -0700 (Sat, 12 Apr 2008) | 1 line
  
  forgot some files...
........
  r8556 | huybrechts | 2008-04-12 08:34:31 -0700 (Sat, 12 Apr 2008) | 1 line
  
  an authorization strategy that provides project-based access control (not usable on its own)
........
  r8793 | huybrechts | 2008-04-22 14:39:57 -0700 (Tue, 22 Apr 2008) | 1 line
  
  [issue #1573] allow plugins to contribute ServletFilters
........
  r8803 | huybrechts | 2008-04-23 10:46:09 -0700 (Wed, 23 Apr 2008) | 1 line
  
  added ignores
........
  r8804 | huybrechts | 2008-04-23 10:52:11 -0700 (Wed, 23 Apr 2008) | 1 line
  
  added ignores
........
  r8805 | huybrechts | 2008-04-23 10:54:12 -0700 (Wed, 23 Apr 2008) | 1 line
  
  added ignores
........
  r8806 | huybrechts | 2008-04-23 10:59:13 -0700 (Wed, 23 Apr 2008) | 1 line
  
  Issue 1158
........
  r8858 | huybrechts | 2008-04-25 08:17:41 -0700 (Fri, 25 Apr 2008) | 1 line
  
  bugfixes
........
  r9027 | huybrechts | 2008-05-04 12:20:34 -0700 (Sun, 04 May 2008) | 1 line
  
  Issue 1158 - fixing permission checks in jelly
........
  r9028 | huybrechts | 2008-05-04 12:22:36 -0700 (Sun, 04 May 2008) | 1 line
  
  creating SFEE releases from Hudson
........


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@9699 71c3de6d-444a-0410-be80-ed276b4c234a
上级 bae1fc3d
package hudson;
import hudson.maven.ExecutedMojo;
import hudson.model.*;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Items;
import hudson.model.Job;
import hudson.model.JobPropertyDescriptor;
import hudson.model.ModelObject;
import hudson.model.Node;
import hudson.model.Project;
import hudson.model.Run;
import hudson.model.TopLevelItem;
import hudson.model.View;
import hudson.search.SearchableModelObject;
import hudson.security.AccessControlled;
import hudson.security.AuthorizationStrategy;
import hudson.security.Permission;
import hudson.security.SecurityRealm;
import hudson.slaves.ComputerLauncher;
import hudson.slaves.RetentionStrategy;
import hudson.tasks.BuildStep;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrappers;
import hudson.tasks.Builder;
import hudson.tasks.Publisher;
import hudson.security.SecurityRealm;
import hudson.security.AuthorizationStrategy;
import hudson.security.Permission;
import hudson.util.Area;
import hudson.slaves.ComputerLauncher;
import hudson.slaves.RetentionStrategy;
import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
import org.apache.commons.jelly.JellyContext;
import org.apache.commons.jexl.parser.ASTSizeFunction;
import org.apache.commons.jexl.util.Introspector;
import org.apache.commons.jelly.JellyContext;
import org.kohsuke.stapler.Ancestor;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
......@@ -425,7 +440,15 @@ public class Functions {
}
public static void checkPermission(Permission permission) throws IOException, ServletException {
Hudson.getInstance().getACL().checkPermission(permission);
if (permission != null) {
Hudson.getInstance().getACL().checkPermission(permission);
}
}
public static void checkPermission(AccessControlled object, Permission permission) throws IOException, ServletException {
if (permission != null) {
object.checkPermission(permission);
}
}
/**
......@@ -438,6 +461,10 @@ public class Functions {
return permission==null || Hudson.getInstance().getACL().hasPermission(permission);
}
public static boolean hasPermission(AccessControlled object, Permission permission) throws IOException, ServletException {
return permission==null || object.hasPermission(permission);
}
public static void adminCheck(StaplerRequest req, StaplerResponse rsp, Object required, Permission permission) throws IOException, ServletException {
// this is legacy --- all views should be eventually converted to
// the permission based model.
......
......@@ -3,6 +3,7 @@ package hudson.model;
import hudson.XmlFile;
import hudson.Util;
import hudson.Functions;
import hudson.security.AccessControlled;
import hudson.security.Permission;
import hudson.security.ACL;
import org.kohsuke.stapler.export.Exported;
......@@ -27,7 +28,7 @@ import javax.servlet.ServletException;
// Item doesn't necessarily have to be Actionable, but
// Java doesn't let multiple inheritance.
@ExportedBean
public abstract class AbstractItem extends Actionable implements Item, HttpDeletable {
public abstract class AbstractItem extends Actionable implements Item, HttpDeletable, AccessControlled {
/**
* Project name.
*/
......@@ -164,8 +165,7 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet
* Returns the {@link ACL} for this object.
*/
public ACL getACL() {
// TODO: this object should have its own ACL
return Hudson.getInstance().getACL();
return Hudson.getInstance().getAuthorizationStrategy().getACL(this);
}
/**
......
......@@ -616,7 +616,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
}
Launcher launcher = workspace != null ? workspace.createLauncher(listener) : null;
LOGGER.info("Polling SCM changes of "+ getName());
LOGGER.fine("Polling SCM changes of "+ getName());
return scm.pollChanges(this, launcher, workspace, listener );
} catch (AbortException e) {
listener.fatalError(Messages.AbstractProject_Aborted());
......
......@@ -7,25 +7,32 @@ import hudson.slaves.RetentionStrategy;
import hudson.node_monitors.NodeMonitor;
import hudson.remoting.Channel;
import hudson.remoting.VirtualChannel;
import hudson.security.ACL;
import hudson.security.AccessControlled;
import hudson.security.Permission;
import hudson.security.PermissionGroup;
import hudson.tasks.BuildWrapper;
import hudson.tasks.Publisher;
import hudson.util.DaemonThreadFactory;
import hudson.util.RemotingDiagnostics;
import hudson.util.RunList;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.LogRecord;
import javax.servlet.ServletException;
import org.jvnet.localizer.Localizable;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
......@@ -53,8 +60,9 @@ import org.kohsuke.stapler.export.ExportedBean;
* @author Kohsuke Kawaguchi
*/
@ExportedBean
public abstract class Computer extends AbstractModelObject {
private final CopyOnWriteArrayList<Executor> executors = new CopyOnWriteArrayList<Executor>();
public abstract class Computer extends AbstractModelObject implements AccessControlled {
private final CopyOnWriteArrayList<Executor> executors = new CopyOnWriteArrayList<Executor>();
private int numExecutors;
......@@ -74,6 +82,18 @@ public abstract class Computer extends AbstractModelObject {
setNode(node);
}
public ACL getACL() {
return Hudson.getInstance().getAuthorizationStrategy().getACL(this);
}
public void checkPermission(Permission permission) {
getACL().checkPermission(permission);
}
public boolean hasPermission(Permission permission) {
return getACL().hasPermission(permission);
}
/**
* Gets the channel that can be used to run a program on this computer.
*
......@@ -385,7 +405,7 @@ public abstract class Computer extends AbstractModelObject {
}
public void doToggleOffline( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
checkPermission(Hudson.ADMINISTER);
setTemporarilyOffline(!temporarilyOffline);
rsp.forwardToPreviousPage(req);
......@@ -400,7 +420,7 @@ public abstract class Computer extends AbstractModelObject {
*/
public void doDumpExportTable( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
// this is a debug probe and may expose sensitive information
Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
checkPermission(Hudson.ADMINISTER);
rsp.setContentType("text/plain");
rsp.setCharacterEncoding("UTF-8");
......@@ -412,7 +432,7 @@ public abstract class Computer extends AbstractModelObject {
public void doScript( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
// ability to run arbitrary script is dangerous,
// so tie it to the admin access
Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
checkPermission(Hudson.ADMINISTER);
String text = req.getParameter("script");
if(text!=null) {
......
......@@ -245,6 +245,8 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
*/
private List<ListView> views; // can't initialize it eagerly for backward compatibility
private transient MyView myView = new MyView(this);
private transient final FingerprintMap fingerprintMap = new FingerprintMap();
/**
......@@ -702,9 +704,11 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
return v;
}
}
if(this.getViewName().equals(name))
if (this.getViewName().equals(name)) {
return this;
else
} else if (myView.getViewName().equals(name)) {
return myView;
} else
return null;
}
......@@ -715,12 +719,13 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
public synchronized View[] getViews() {
if(views==null)
views = new ArrayList<ListView>();
View[] r = new View[views.size()+1];
View[] r = new View[views.size()+2];
views.toArray(r);
// sort Views and put "all" at the very beginning
r[r.length-1] = r[0];
Arrays.sort(r,1,r.length, View.SORTER);
r[0] = this;
r[r.length-2] = r[0];
r[r.length-1] = r[1];
Arrays.sort(r,2,r.length, View.SORTER);
r[0] = myView;
r[1] = this;
return r;
}
......
......@@ -61,7 +61,7 @@ public class Label implements Comparable<Label>, ModelObject {
*/
public boolean isOffline() {
for (Node n : getNodes()) {
if(!n.toComputer().isOffline())
if(n.toComputer() != null && !n.toComputer().isOffline())
return false;
}
return true;
......
package hudson.model;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.servlet.ServletException;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
public class MyView extends View {
private Hudson owner;
private String description;
public MyView(Hudson owner){
this.owner = owner;
}
@Override
public boolean contains(TopLevelItem item) {
return (item instanceof Job) && ((Job) item).hasPermission(Hudson.ADMINISTER);
}
@Override
public Item doCreateItem(StaplerRequest req, StaplerResponse rsp)
throws IOException, ServletException {
return owner.doCreateItem(req, rsp);
}
@Override
public String getDescription() {
return description;
}
@Override
public TopLevelItem getItem(String name) {
return owner.getItem(name);
}
@Override
public Collection<TopLevelItem> getItems() {
List<TopLevelItem> items = new ArrayList<TopLevelItem>();
for (TopLevelItem item: owner.getItems()) {
if ((item instanceof Job) && ((Job) item).hasPermission(Job.CONFIGURE)) {
items.add(item);
}
}
return Collections.unmodifiableList(items);
}
@Override
public String getUrl() {
return "view/" + getViewName() + "/";
}
@Override
public String getViewName() {
return "My Projects";
}
public String getDisplayName() {
return "My Projects";
}
public TopLevelItem getJob(String name) {
return getItem(name);
}
/**
* Accepts the new description.
*/
public synchronized void doSubmitDescription( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
checkPermission(CONFIGURE);
req.setCharacterEncoding("UTF-8");
description = req.getParameter("description");
owner.save();
rsp.sendRedirect("."); // go to the top page
}
}
......@@ -9,6 +9,7 @@ import hudson.FilePath;
import hudson.Util;
import static hudson.Util.combine;
import hudson.XmlFile;
import hudson.security.AccessControlled;
import hudson.security.Permission;
import hudson.security.PermissionGroup;
import hudson.security.ACL;
......@@ -71,7 +72,7 @@ import java.util.logging.Logger;
*/
@ExportedBean
public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,RunT>>
extends Actionable implements ExtensionPoint, Comparable<RunT> {
extends Actionable implements ExtensionPoint, Comparable<RunT>, AccessControlled {
protected transient final JobT project;
......@@ -664,6 +665,10 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
getACL().checkPermission(p);
}
public boolean hasPermission(Permission p) {
return getACL().hasPermission(p);
}
public ACL getACL() {
// for now, don't maintain ACL per run, and do it at project level
return getParent().getACL();
......
package hudson.model;
import hudson.Util;
import hudson.security.AccessControlled;
import hudson.security.Permission;
import hudson.security.ACL;
import hudson.security.PermissionGroup;
......@@ -33,7 +34,7 @@ import java.util.Map;
* @author Kohsuke Kawaguchi
*/
@ExportedBean
public abstract class View extends AbstractModelObject {
public abstract class View extends AbstractModelObject implements AccessControlled {
/**
* Gets all the items in this collection in a read-only view.
......@@ -91,17 +92,17 @@ public abstract class View extends AbstractModelObject {
* Returns the {@link ACL} for this object.
*/
public ACL getACL() {
// TODO: this object should have its own ACL
return Hudson.getInstance().getACL();
return Hudson.getInstance().getAuthorizationStrategy().getACL(this);
}
/**
* Short for {@code getACL().checkPermission(p)}
*/
public void checkPermission(Permission p) {
getACL().checkPermission(p);
}
public boolean hasPermission(Permission p) {
return getACL().hasPermission(p);
}
@ExportedBean(defaultVisibility=2)
public static final class UserInfo implements Comparable<UserInfo> {
private final User user;
......
package hudson.security;
public interface AccessControlled {
void checkPermission(Permission permission);
boolean hasPermission(Permission permission);
}
package hudson.security;
import hudson.ExtensionPoint;
import hudson.model.AbstractItem;
import hudson.model.AbstractProject;
import hudson.model.Computer;
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.model.View;
import hudson.util.DescriptorList;
import org.acegisecurity.Authentication;
import org.kohsuke.stapler.StaplerRequest;
import java.io.Serializable;
import java.util.List;
import java.util.Collection;
import java.util.Collections;
import net.sf.json.JSONObject;
import org.acegisecurity.Authentication;
import org.kohsuke.stapler.StaplerRequest;
/**
* Controls authorization throughout Hudson.
*
......@@ -44,7 +48,23 @@ public abstract class AuthorizationStrategy implements Describable<Authorization
*/
public abstract ACL getRootACL();
/**
public ACL getACL(AbstractProject<?,?> project) {
return getRootACL();
}
public ACL getACL(View item) {
return getRootACL();
}
public ACL getACL(AbstractItem item) {
return getRootACL();
}
public ACL getACL(Computer computer) {
return getRootACL();
}
/**
* Returns the list of all group/role names used in this authorization strategy,
* and the ACL returned from the {@link #getRootACL()} method.
* <p>
......
package hudson.security;
import hudson.model.AbstractProject;
import hudson.model.Computer;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.model.Item;
import hudson.model.View;
import hudson.util.FormFieldValidator;
import java.util.Collections;
import java.util.List;
import net.sf.json.JSONObject;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.acls.sid.GrantedAuthoritySid;
import org.kohsuke.stapler.StaplerRequest;
/**
* {@link AuthorizationStrategy} that grants control based on owned permissions.
*/
// TODO: ask Tom to explain what this class is.
public class ProjectBasedAuthorizationStrategy extends AuthorizationStrategy {
@Override
public ACL getRootACL() {
return ROOT_ACL;
}
@Override
public ACL getACL(AbstractProject<?, ?> project) {
SparseACL acl = new SparseACL(ROOT_ACL);
acl.add(new GrantedAuthoritySid(createItemAuthority(project)), Permission.FULL_CONTROL, true);
return acl;
}
@Override
public ACL getACL(Computer computer) {
SparseACL acl = new SparseACL(ROOT_ACL);
acl.add(ACL.ANONYMOUS, Hudson.ADMINISTER, false);
acl.add(ACL.EVERYONE, Hudson.ADMINISTER, true);
return acl;
}
@Override
public ACL getACL(View view) {
SparseACL acl = new SparseACL(ROOT_ACL);
acl.add(ACL.ANONYMOUS, Permission.CREATE, false);
acl.add(ACL.EVERYONE, Permission.CREATE, true);
return acl;
}
public List<String> getGroups() {
return Collections.emptyList();
}
public static final SparseACL ROOT_ACL = new SparseACL(null);
static {
ROOT_ACL.add(new GrantedAuthoritySid("admin"), Permission.FULL_CONTROL, true);
ROOT_ACL.add(ACL.ANONYMOUS,FormFieldValidator.CHECK,false);
ROOT_ACL.add(ACL.EVERYONE,FormFieldValidator.CHECK,true);
ROOT_ACL.add(ACL.EVERYONE,Permission.READ,true);
ROOT_ACL.add(ACL.EVERYONE,Permission.FULL_CONTROL,false);
}
public GrantedAuthority createItemAuthority(Item item) {
return new GrantedAuthorityImpl(item.getFullName());
}
public Descriptor<AuthorizationStrategy> getDescriptor() {
return DESCRIPTOR;
}
public static final Descriptor<AuthorizationStrategy> DESCRIPTOR = new Descriptor<AuthorizationStrategy>(ProjectBasedAuthorizationStrategy.class) {
public String getDisplayName() {
return "Project Based Access Control";
}
public AuthorizationStrategy newInstance(StaplerRequest req, JSONObject formData) throws FormException {
return new ProjectBasedAuthorizationStrategy();
}
public String getHelpFile() {
return "/help/security/full-control-once-logged-in.html";
}
};
}
......@@ -180,7 +180,7 @@ public final class SlaveComputer extends Computer {
}
public void doDoDisconnect(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
checkPermission(Hudson.ADMINISTER);
disconnect();
rsp.sendRedirect(".");
}
......
package hudson.tasks;
import hudson.ExtensionPoint;
import hudson.Plugin;
import hudson.scm.SCM;
import hudson.scm.CVSSCM;
import hudson.scm.SubversionSCM;
import hudson.model.User;
import hudson.model.AbstractProject;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Finds full name off the user when none is specified.
*
* <p>
* This is an extension point of Hudson. Plugins tha contribute new implementation
* of this class must register it to {@link #LIST}. The typical way to do this is:
*
* <pre>
* class PluginImpl extends {@link Plugin} {
* public void start() {
* ...
* UserNameResolver.LIST.add(new UserNameResolver());
* }
* }
* </pre>
*
* @author Kohsuke Kawaguchi
* @sine 1.192
*/
public abstract class UserNameResolver implements ExtensionPoint {
/**
* Finds full name of the given user.
*
* <p>
* This method is called when a {@link User} without explicitly name is used.
*
* <p>
* When multiple resolvers are installed, they are consulted in order and
* the search will be over when a name is found by someoene.
*
* <p>
* Since {@link UserNameResolver} is singleton, this method can be invoked concurrently
* from multiple threads.
*
* @return
* null if the inference failed.
*/
public abstract String findNameFor(User u);
public static String resolve(User u) {
for (UserNameResolver r : LIST) {
String name = r.findNameFor(u);
if(name!=null) return name;
}
return null;
}
/**
* All registered {@link UserNameResolver} implementations.
*/
public static final List<UserNameResolver> LIST = new CopyOnWriteArrayList<UserNameResolver>();
}
package hudson.util;
import static hudson.Util.fixEmpty;
import hudson.EnvVars;
import hudson.FilePath;
import hudson.Util;
import hudson.EnvVars;
import static hudson.Util.fixEmpty;
import hudson.model.AbstractProject;
import hudson.model.Hudson;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import hudson.security.Permission;
import javax.servlet.ServletException;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.HttpURLConnection;
import javax.servlet.ServletException;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/**
* Base class that provides the framework for doing on-the-fly form field validation.
......@@ -28,29 +31,35 @@ import java.net.HttpURLConnection;
* @author Kohsuke Kawaguchi
*/
public abstract class FormFieldValidator {
protected final StaplerRequest request;
public static final Permission CHECK = new Permission(Hudson.PERMISSIONS, "check", Permission.FULL_CONTROL);
protected final StaplerRequest request;
protected final StaplerResponse response;
private final boolean isAdminOnly;
private final Permission permission;
/**
*
* @param adminOnly
* Pass true to only let admin users to run the check. This is necessary
* for security reason, so that unauthenticated user cannot obtain sensitive
* information or run a process that may have side-effect.
*/
protected FormFieldValidator(StaplerRequest request, StaplerResponse response, boolean adminOnly) {
this(request, response, CHECK);
}
protected FormFieldValidator(StaplerRequest request, StaplerResponse response, Permission permission) {
this.request = request;
this.response = response;
isAdminOnly = adminOnly;
this.permission = permission;
}
/**
* Runs the validation code.
*/
public final void process() throws IOException, ServletException {
if(isAdminOnly && !Hudson.adminCheck(request,response))
return; // failed check
Hudson.getInstance().checkPermission(permission);
check();
}
......
package hudson.util;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
/**
* Servlet {@link Filter} that chains multiple {@link Filter}s, provided by plugins
*
*/
public class PluginServletFilter implements Filter {
public static CopyOnWriteList<Filter> LIST = new CopyOnWriteList<Filter>();
public PluginServletFilter() {
}
public void init(FilterConfig filterConfig) throws ServletException {
for (Filter f : LIST)
f.init(filterConfig);
}
public void doFilter(ServletRequest request, ServletResponse response, final FilterChain chain) throws IOException, ServletException {
new FilterChain() {
private int position=0;
// capture the array for thread-safety
private final Filter[] filters = LIST.toArray(new Filter[0]);
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if(position==filters.length) {
// reached to the end
chain.doFilter(request,response);
} else {
// call next
filters[position++].doFilter(request,response,this);
}
}
}.doFilter(request,response);
}
public void destroy() {
for (Filter f : LIST)
f.destroy();
}
}
......@@ -3,7 +3,7 @@
<st:include page="sidepanel.jelly" />
<l:main-panel>
<h1>${%Project} ${it.name}</h1>
<t:editableDescription adminOnly="true"/>
<t:editableDescription permission="${app.ADMINISTER}"/>
<st:include page="ajaxMatrix.jelly" />
......
......@@ -3,7 +3,7 @@
<st:include page="sidepanel.jelly" />
<l:main-panel>
<h1>${it.pronoun} ${it.displayName}</h1>
<t:editableDescription adminOnly="true"/>
<t:editableDescription permission="${app.ADMINISTER}"/>
<p:projectActionFloatingBox />
......
......@@ -22,7 +22,7 @@
</t:buildCaption>
<div>
<t:editableDescription adminOnly="true" />
<t:editableDescription permission="${app.ADMINISTER}" />
</div>
<table style="margin-top: 1em; margin-left:1em;">
......
......@@ -2,7 +2,7 @@
Entrance to the configuration page
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:s="/lib/form">
<l:layout title="Nodes" secured="true">
<l:layout title="Nodes" permission="${app.ADMINISTER}">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<j:set var="monitors" value="${it._monitors}"/>
......
......@@ -2,7 +2,7 @@
Config page
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:s="/lib/form">
<l:layout norefresh="true" permission="${app.ADMINISTER}">
<l:layout norefresh="true" permission="${it.CONFIGURE}">
<st:include page="sidepanel.jelly" />
<l:main-panel xmlns:local="local">
<s:form method="post" action="configSubmit">
......
......@@ -2,7 +2,7 @@
Log view
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<l:layout title="Log" secured="true">
<l:layout title="Log" permission="${app.ADMINISTER}">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<h1><img src="images/48x48/clipboard.gif" />${%Hudson Log}</h1>
......
......@@ -2,7 +2,7 @@
Config page
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:s="/lib/form">
<l:layout secured="true" norefresh="true">
<l:layout permission="${app.ADMINISTER}" norefresh="true">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<s:form method="post" action="configSubmit">
......
......@@ -2,15 +2,13 @@
Various system information for diagnostics
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<l:layout>
<l:layout permission="${app.ADMINISTER}">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<l:isAdmin>
<h1>${%System Properties}</h1>
<t:propertyTable items="${h.systemProperties}" />
<h1>${%Environment Variables}</h1>
<t:propertyTable items="${h.envVars}" />
</l:isAdmin>
</l:main-panel>
</l:layout>
</j:jelly>
......@@ -2,7 +2,7 @@
Produces stack dump of all threads by using JMX.
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<l:layout secure="true">
<l:layout permission="${app.ADMINISTER}">
<st:include page="sidepanel.jelly" />
<l:main-panel>
......
......@@ -3,7 +3,7 @@
<st:include page="sidepanel.jelly" />
<l:main-panel>
<h1>${it.pronoun} ${it.displayName}</h1>
<t:editableDescription adminOnly="true"/>
<t:editableDescription permission="${app.ADMINISTER}"/>
<j:if test="${it.disabled}">
<div class="warning">
......
<div>
This view has no jobs.
</div>
\ No newline at end of file
......@@ -5,7 +5,7 @@
<st:include page="sidepanel.jelly" />
<l:main-panel>
<div id="view-message">
<t:editableDescription adminOnly="true"/>
<t:editableDescription permission="${app.ADMINISTER}"/>
</div>
<j:set var="items" value="${it.items}"/>
<j:choose>
......@@ -20,7 +20,7 @@
<j:forEach var="v" items="${app.views}">
<l:tab name="${v.viewName}" active="${v==it}" href="${rootURL}/${v.url}" />
</j:forEach>
<j:if test="${h.hasPermission(it.CREATE)}">
<j:if test="${it.hasPermission(it.CREATE)}">
<l:tab name="+" href="${rootURL}/newView" active="false" />
</j:if>
</l:tabBar>
......
......@@ -23,7 +23,7 @@
<ol>
<j:forEach var="c" items="${b.changeSet.iterator()}" varStatus="loop">
<li>
<li value="${c.revision}">
${c.msgAnnotated}
&#8212;
......
......@@ -8,7 +8,7 @@
</div>
</j:when>
<j:when test="${it.offline and !it.temporarilyOffline}">
<l:isAdmin>
<l:isAdmin><!-- TODO: we need a permission to launch a slave -->
<p>
<a href="slave-agent.jnlp">
<img src="${imagesURL}/webstart.gif" alt="launch agent" />
......
......@@ -9,7 +9,7 @@
${it.description}
</div>
<l:isAdmin>
<l:hasPermission permission="${permission}">
<div align="right"><a href="editDescription" onclick="return replaceDescription();">
<img src="${imagesURL}/16x16/notepad.gif" />
<j:choose>
......@@ -21,6 +21,6 @@
</j:otherwise>
</j:choose>
</a></div>
</l:isAdmin>
</l:hasPermission>
</div>
</j:jelly>
\ No newline at end of file
<!--
Attributes:
permission: the body is only rendered if permission is null, or the user has the permission
-->
<j:jelly xmlns:j="jelly:core" xmlns:d="jelly:define" xmlns:s="jelly:stapler">
<j:if test="${h.hasPermission(it, permission)}">
<d:invokeBody />
</j:if>
</j:jelly>
\ No newline at end of file
......@@ -31,8 +31,7 @@
<j:set var="imagesURL" value="${rootURL}${h.resourcePath}/images" />
<html>
<head>
<!-- if this page needs to be secured, make sure the user is admin -->
${h.adminCheck(request,response,secured,permission)}
${h.checkPermission(it,permission)}
<title>${h.appendIfNotNull(title, ' [Hudson]', 'Hudson')}</title>
<link rel="stylesheet" href="${resURL}/css/style.css" type="text/css" />
......
......@@ -8,7 +8,7 @@
permission: permission object. If specified, the link will be displayed only if you have a permission (optional)
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler">
<j:if test="${h.hasPermission(attrs.permission)}">
<j:if test="${h.hasPermission(it,permission)}">
<div class="task">
<a href="${href}" onclick="${attrs.onclick}">
<img width="24" height="24" style="margin: 2px;" src="${rootURL}${h.ifThenElse(icon.startsWith('images/'),h.resourcePath,'')}/${icon}"/>
......
......@@ -205,6 +205,16 @@
</build>
<dependencies>
<dependency>
<groupId>jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.1_3</version>
</dependency>
<dependency>
<groupId>org.jvnet.hudson.main</groupId>
<artifactId>jnlp-agent</artifactId>
......
......@@ -59,6 +59,15 @@
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>plugins-filter</filter-name>
<filter-class>hudson.util.PluginServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>plugins-filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Uncomment this if you are protecting your entire hudson setup
from public view. See note above about the filter.
<filter-mapping>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册