提交 24dec27e 编写于 作者: J Jesse Glick

Merge branch 'master' into security-settings-save

......@@ -234,6 +234,7 @@ public abstract class ItemGroupMixIn {
}
src.getDescriptor().checkApplicableIn(parent);
acl.getACL().checkCreatePermission(parent, src.getDescriptor());
ItemListener.checkBeforeCopy(src, parent);
T result = (T)createProject(src.getDescriptor(),name,false);
......
......@@ -32,6 +32,7 @@ import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.annotation.Nonnull;
import jenkins.security.NotReallyRoleSensitiveCallable;
/**
* Controls mutual exclusion of {@link ResourceList}.
......@@ -77,20 +78,18 @@ public class ResourceController {
*/
public void execute(@Nonnull Runnable task, final ResourceActivity activity ) throws InterruptedException {
final ResourceList resources = activity.getResourceList();
_withLock(new Runnable() {
_withLock(new NotReallyRoleSensitiveCallable<Void,InterruptedException>() {
@Override
public void run() {
while(inUse.isCollidingWith(resources))
try {
// TODO revalidate the resource list after re-acquiring lock, for now we just let the build fail
_await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
public Void call() throws InterruptedException {
while (inUse.isCollidingWith(resources)) {
// TODO revalidate the resource list after re-acquiring lock, for now we just let the build fail
_await();
}
// we have a go
inProgress.add(activity);
inUse = ResourceList.union(inUse,resources);
inUse = ResourceList.union(inUse, resources);
return null;
}
});
......@@ -184,5 +183,11 @@ public class ResourceController {
return callable.call();
}
}
protected <V, T extends Throwable> V _withLock(hudson.remoting.Callable<V,T> callable) throws T {
synchronized (this) {
return callable.call();
}
}
}
......@@ -24,17 +24,18 @@
package hudson.model.listeners;
import com.google.common.base.Function;
import hudson.AbortException;
import hudson.ExtensionPoint;
import hudson.ExtensionList;
import hudson.Extension;
import hudson.model.Failure;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Items;
import hudson.security.ACL;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import jenkins.security.NotReallyRoleSensitiveCallable;
import org.acegisecurity.AccessDeniedException;
/**
* Receives notifications about CRUD operations of {@link Item}.
......@@ -56,6 +57,18 @@ public class ItemListener implements ExtensionPoint {
public void onCreated(Item item) {
}
/**
* Called before a job is copied into a new parent, providing the ability to veto the copy operation before it
* starts.
*
* @param src the item being copied
* @param parent the proposed parent
* @throws Failure to veto the operation.
* @since TODO
*/
public void onCheckCopy(Item src, ItemGroup parent) throws Failure {
}
/**
* Called after a new job is created by copying from an existing job.
*
......@@ -180,6 +193,27 @@ public class ItemListener implements ExtensionPoint {
});
}
/**
* Call before a job is copied into a new parent, to allow the {@link ItemListener} implementations the ability
* to veto the copy operation before it starts.
*
* @param src the item being copied
* @param parent the proposed parent
* @throws Failure if the copy operation has been vetoed.
* @since TODO
*/
public static void checkBeforeCopy(final Item src, final ItemGroup parent) throws Failure {
for (ItemListener l : all()) {
try {
l.onCheckCopy(src, parent);
} catch (Failure e) {
throw e;
} catch (RuntimeException x) {
LOGGER.log(Level.WARNING, "failed to send event to listener of " + l.getClass(), x);
}
}
}
public static void fireOnCreated(final Item item) {
forAll(new Function<ItemListener,Void>() {
@Override public Void apply(ItemListener l) {
......
......@@ -23,11 +23,18 @@
*/
package hudson.jobs;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.*;
import hudson.AbortException;
import hudson.model.Failure;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.listeners.ItemListener;
import java.net.URL;
import java.text.MessageFormat;
import org.acegisecurity.AccessDeniedException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
......@@ -39,6 +46,7 @@ import com.gargoylesoftware.htmlunit.HttpMethod;
import com.gargoylesoftware.htmlunit.WebRequest;
import hudson.model.FreeStyleProject;
import org.jvnet.hudson.test.MockFolder;
import org.jvnet.hudson.test.TestExtension;
/**
* Tests the /createItem REST API.
......@@ -81,6 +89,33 @@ public class CreateItemTest {
assertEquals("Creating job from copy should succeed.", 200, result);
}
@Issue("JENKINS-34691")
@Test
public void vetoCreateItemFromCopy() throws Exception {
rule.jenkins.setCrumbIssuer(null);
String sourceJobName = "sourceJob";
rule.createFreeStyleProject(sourceJobName);
String newJobName = "newJob";
URL apiURL = new URL(MessageFormat.format(
"{0}createItem?mode=copy&from={1}&name={2}",
rule.getURL().toString(), sourceJobName, newJobName));
WebRequest request = new WebRequest(apiURL, HttpMethod.POST);
deleteContentTypeHeader(request);
int result = ERROR_PRESET;
try {
result = rule.createWebClient()
.getPage(request).getWebResponse().getStatusCode();
} catch (FailingHttpStatusCodeException e) {
result = e.getResponse().getStatusCode();
}
assertEquals("Creating job from copy should fail.", 400, result);
assertThat(rule.jenkins.getItem("newJob"), nullValue());
}
private void deleteContentTypeHeader(WebRequest request) {
request.setEncodingType(null);
}
......@@ -96,4 +131,14 @@ public class CreateItemTest {
assertNotNull(d2.getItem("p3"));
}
@TestExtension("vetoCreateItemFromCopy")
public static class ItemListenerImpl extends ItemListener {
@Override
public void onCheckCopy(Item src, ItemGroup parent) throws Failure {
if ("sourceJob".equals(src.getName())) {
throw new Failure("Go away I don't like you");
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册