提交 2d898fda 编写于 作者: J Jesse Glick

Merge branch 'security-stable-1.596' into security-stable-1.609

......@@ -113,6 +113,7 @@ import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.Authentication;
import org.jenkinsci.bytecode.AdaptField;
import org.jenkinsci.remoting.RoleChecker;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.export.Exported;
......@@ -782,18 +783,68 @@ public class Queue extends ResourceController implements Saveable {
@Exported(inline=true)
public Item[] getItems() {
Snapshot s = this.snapshot;
Item[] r = new Item[s.waitingList.size() + s.blockedProjects.size() + s.buildables.size() +
s.pendings.size()];
s.waitingList.toArray(r);
int idx = s.waitingList.size();
for (BlockedItem p : s.blockedProjects) {
r[idx++] = p;
List<Item> r = new ArrayList<Item>();
for(WaitingItem p : s.waitingList) {
r = filterItemListBasedOnPermissions(r, p);
}
for (BlockedItem p : s.blockedProjects){
r = filterItemListBasedOnPermissions(r, p);
}
for (BuildableItem p : reverse(s.buildables)) {
r = filterItemListBasedOnPermissions(r, p);
}
for (BuildableItem p : reverse(s.pendings)) {
r= filterItemListBasedOnPermissions(r, p);
}
Item[] items = new Item[r.size()];
r.toArray(items);
return items;
}
private List<Item> filterItemListBasedOnPermissions(List<Item> r, Item t) {
if (t.task instanceof hudson.model.Item) {
if (((hudson.model.Item)t.task).hasPermission(hudson.model.Item.READ)) {
r.add(t);
}
}
return r;
}
/**
* Returns an array of Item for which it is only visible the name of the task.
*
* Generally speaking the array is sorted such that the items that are most likely built sooner are
* at the end.
*/
@Restricted(NoExternalUse.class)
@Exported(inline=true)
public StubItem[] getDiscoverableItems() {
Snapshot s = this.snapshot;
List<StubItem> r = new ArrayList<StubItem>();
for(WaitingItem p : s.waitingList) {
r = filterDiscoverableItemListBasedOnPermissions(r, p);
}
for (BlockedItem p : s.blockedProjects){
r = filterDiscoverableItemListBasedOnPermissions(r, p);
}
for (BuildableItem p : reverse(s.buildables)) {
r[idx++] = p;
r = filterDiscoverableItemListBasedOnPermissions(r, p);
}
for (BuildableItem p : reverse(s.pendings)) {
r[idx++] = p;
r= filterDiscoverableItemListBasedOnPermissions(r, p);
}
StubItem[] items = new StubItem[r.size()];
r.toArray(items);
return items;
}
private List<StubItem> filterDiscoverableItemListBasedOnPermissions(List<StubItem> r, Item t) {
if (t.task instanceof hudson.model.Item) {
if (!((hudson.model.Item)t.task).hasPermission(hudson.model.Item.READ) && ((hudson.model.Item)t.task).hasPermission(hudson.model.Item.DISCOVER)) {
r.add(new StubItem(new StubTask(t.task)));
}
}
return r;
}
......@@ -2117,6 +2168,42 @@ public class Queue extends ResourceController implements Saveable {
}
/**
* A Stub class for {@link Task} which exposes only the name of the Task to be displayed when the user
* has DISCOVERY permissions only.
*/
@Restricted(NoExternalUse.class)
@ExportedBean(defaultVisibility = 999)
public static class StubTask {
private String name;
public StubTask(@Nonnull Queue.Task base) {
this.name = base.getName();
}
@Exported
public String getName() {
return name;
}
}
/**
* A Stub class for {@link Item} which exposes only the name of the Task to be displayed when the user
* has DISCOVERY permissions only.
*/
@Restricted(NoExternalUse.class)
@ExportedBean(defaultVisibility = 999)
public class StubItem {
@Exported public StubTask task;
public StubItem(StubTask task) {
this.task = task;
}
}
/**
* An optional interface for actions on Queue.Item.
* Lets the action cooperate in queue management.
......
......@@ -91,7 +91,7 @@ public class DefaultJnlpSlaveReceiver extends JnlpAgentReceiver {
String handshakeSecret = handshake.getRequestProperty("Secret-Key");
// Verify that the slave secret matches the handshake secret.
if (!computer.getJnlpMac().equals(handshakeSecret)) {
LOGGER.log(Level.WARNING, "An attempt was made to connect as {0} from {1} with an incorrect secret", new Object[]{nodeName, handshake.getSocket().getRemoteSocketAddress()});
LOGGER.log(Level.WARNING, "An attempt was made to connect as {0} from {1} with an incorrect secret", new Object[]{nodeName, handshake.getSocket()!=null?handshake.getSocket().getRemoteSocketAddress():null});
return false;
} else {
return true;
......
......@@ -23,6 +23,8 @@
*/
package hudson.model;
import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.DomNode;
import com.gargoylesoftware.htmlunit.html.HtmlFileInput;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
......@@ -41,11 +43,16 @@ import hudson.model.Queue.BlockedItem;
import hudson.model.Queue.Executable;
import hudson.model.Queue.WaitingItem;
import hudson.model.queue.AbstractQueueTask;
import hudson.model.queue.CauseOfBlockage;
import hudson.model.queue.QueueTaskDispatcher;
import hudson.model.queue.QueueTaskFuture;
import hudson.model.queue.ScheduleResult;
import hudson.model.queue.SubTask;
import hudson.security.ACL;
import hudson.security.AuthorizationMatrixProperty;
import hudson.security.GlobalMatrixAuthorizationStrategy;
import hudson.security.Permission;
import hudson.security.ProjectMatrixAuthorizationStrategy;
import hudson.security.SparseACL;
import hudson.slaves.DumbSlave;
import hudson.slaves.DummyCloudImpl;
......@@ -61,7 +68,10 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
......@@ -99,6 +109,7 @@ import org.jvnet.hudson.test.SequenceLock;
import org.jvnet.hudson.test.SleepBuilder;
import org.jvnet.hudson.test.TestBuilder;
import org.jvnet.hudson.test.recipes.LocalData;
import org.jvnet.hudson.test.TestExtension;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.bio.SocketConnector;
import org.mortbay.jetty.servlet.ServletHandler;
......@@ -555,11 +566,11 @@ public class QueueTest {
FreeStyleBuild b = v.waitForStart();
assertEquals(1,b.getNumber());
assertTrue(b.isBuilding());
assertSame(p,b.getProject());
assertSame(p, b.getProject());
ev.signal(); // let the build complete
FreeStyleBuild b2 = r.assertBuildStatusSuccess(v);
assertSame(b,b2);
assertSame(b, b2);
}
/**
......@@ -779,4 +790,65 @@ public class QueueTest {
"B finished at " + buildBEndTime + ", C started at " + buildC.getStartTimeInMillis(),
buildC.getStartTimeInMillis() >= buildBEndTime);
}
@Test
public void queueApiOutputShouldBeFilteredByUserPermission() throws Exception {
r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
ProjectMatrixAuthorizationStrategy str = new ProjectMatrixAuthorizationStrategy();
str.add(Jenkins.READ, "bob");
str.add(Jenkins.READ, "alice");
str.add(Jenkins.READ, "james");
r.jenkins.setAuthorizationStrategy(str);
FreeStyleProject project = r.createFreeStyleProject("project");
Map<Permission, Set<String>> permissions = new HashMap<Permission, Set<String>>();
permissions.put(Item.READ, Collections.singleton("bob"));
permissions.put(Item.DISCOVER, Collections.singleton("james"));
AuthorizationMatrixProperty prop1 = new AuthorizationMatrixProperty(permissions);
project.addProperty(prop1);
project.getBuildersList().add(new SleepBuilder(10));
project.scheduleBuild2(0);
JenkinsRule.WebClient webClient = r.createWebClient();
webClient.login("bob", "bob");
XmlPage p = webClient.goToXml("/queue/api/xml");
//bob has permission on the project and will be able to see it in the queue together with information such as the URL and the name.
for (DomNode element: p.getFirstChild().getFirstChild().getChildNodes()){
if(element.getNodeName().equals("task")){
assertEquals(((DomElement)element).getElementsByTagName("name").size(),1);
assertEquals(((DomElement) element).getElementsByTagName("name").item(0).getFirstChild().toString(), "project");
assertEquals(((DomElement)element).getElementsByTagName("url").size(),1);
}
}
webClient = r.createWebClient();
webClient.login("alice");
XmlPage p2 = webClient.goToXml("/queue/api/xml");
//alice does not have permission on the project and will not see it in the queue.
assertEquals("<queue></queue>", p2.getContent());
webClient = r.createWebClient();
webClient.login("james");
XmlPage p3 = webClient.goToXml("/queue/api/xml");
//james has DISCOVER permission on the project and will only be able to see the task name.
assertEquals("<queue><discoverableItem><task><name>project</name></task></discoverableItem></queue>",
p3.getContent());
}
//we force the project not to be executed so that it stays in the queue
@TestExtension("queueApiOutputShouldBeFilteredByUserPermission")
public static class MyQueueTaskDispatcher extends QueueTaskDispatcher {
@Override
public CauseOfBlockage canTake(Node node, Queue.BuildableItem item) {
return new CauseOfBlockage() {
@Override
public String getShortDescription() {
return "blocked by canTake";
}
};
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册