Skip to content

Commit

Permalink
Merge pull request #40 from ikedam/feature/JENKINS-20940_relativeFrom…
Browse files Browse the repository at this point in the history
…Matrix

[JENKINS-20940] relative project names from matrix projects.
  • Loading branch information
ikedam committed Jun 29, 2014
2 parents 1cc07c2 + 2b0845a commit b33ceb5
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 28 deletions.
7 changes: 7 additions & 0 deletions pom.xml
Expand Up @@ -28,6 +28,13 @@
<version>1.509</version>
<optional>true</optional>
</dependency>
<!-- Used for UI test -->
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>cloudbees-folder</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down
18 changes: 10 additions & 8 deletions src/main/java/hudson/plugins/copyartifact/CopyArtifact.java
Expand Up @@ -103,13 +103,15 @@ public CopyArtifact(String projectName, String parameters, BuildSelector selecto
// check the permissions only if we can
StaplerRequest req = Stapler.getCurrentRequest();
if (req!=null) {
ItemGroup context = req.findAncestorObject(ItemGroup.class);
if (context == null) context = Jenkins.getInstance();

// Prevents both invalid values and access to artifacts of projects which this user cannot see.
// If value is parameterized, it will be checked when build runs.
if (projectName.indexOf('$') < 0 && Jenkins.getInstance().getItem(projectName, context, Job.class) == null)
projectName = ""; // Ignore/clear bad value to avoid ugly 500 page
AbstractProject<?,?> p = req.findAncestorObject(AbstractProject.class);
if (p != null) {
ItemGroup<?> context = p.getParent();

// Prevents both invalid values and access to artifacts of projects which this user cannot see.
// If value is parameterized, it will be checked when build runs.
if (projectName.indexOf('$') < 0 && Jenkins.getInstance().getItem(projectName, context, Job.class) == null)
projectName = ""; // Ignore/clear bad value to avoid ugly 500 page
}
}

this.project = projectName;
Expand Down Expand Up @@ -251,7 +253,7 @@ public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListene
EnvVars env = build.getEnvironment(listener);
env.overrideAll(build.getBuildVariables()); // Add in matrix axes..
expandedProject = env.expand(project);
Job<?, ?> job = Jenkins.getInstance().getItem(expandedProject, build.getProject().getParent(), Job.class);
Job<?, ?> job = Jenkins.getInstance().getItem(expandedProject, build.getProject().getRootProject().getParent(), Job.class);
if (job != null && !expandedProject.equals(project)
// If projectName is parameterized, need to do permission check on source project.
&& !canReadFrom(job, build)) {
Expand Down
177 changes: 157 additions & 20 deletions src/test/java/hudson/plugins/copyartifact/CopyArtifactTest.java
Expand Up @@ -30,13 +30,16 @@
import hudson.matrix.Combination;
import hudson.matrix.MatrixBuild;
import hudson.matrix.MatrixProject;
import hudson.matrix.TextAxis;
import hudson.matrix.MatrixRun;
import hudson.maven.MavenModuleSet;
import hudson.model.*;
import hudson.model.Cause.UserCause;
import hudson.security.ACL;
import hudson.security.Permission;
import hudson.security.AuthorizationMatrixProperty;
import hudson.security.GlobalMatrixAuthorizationStrategy;
import hudson.security.ProjectMatrixAuthorizationStrategy;
import hudson.slaves.DumbSlave;
import hudson.slaves.SlaveComputer;
import hudson.tasks.ArtifactArchiver;
Expand All @@ -45,13 +48,18 @@
import hudson.tasks.Builder;
import hudson.util.FormValidation;
import hudson.util.VersionNumber;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import jenkins.model.Jenkins;
import org.acegisecurity.context.SecurityContext;

import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.junit.Test;
Expand All @@ -64,6 +72,10 @@
import org.jvnet.hudson.test.UnstableBuilder;
import org.jvnet.hudson.test.recipes.LocalData;

import com.cloudbees.hudson.plugins.folder.Folder;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.google.common.collect.Sets;

import static org.junit.Assert.assertTrue;

/*
Expand Down Expand Up @@ -670,27 +682,83 @@ public void testOptional_MissingArtifact() throws Exception {
* Test that a user is prevented from bypassing permissions on other jobs when configuring
* a copyartifact build step.
*/
@LocalData
public void testPermission() throws Exception {
executeOnServer(new Callable<Object>() {
public Object call() throws Exception {
assertNull("Job should not be accessible to anonymous", hudson.getItem("testJob"));
assertEquals("Should ignore/clear value for inaccessible project", "",
new CopyArtifact("testJob", null, null, null, null, false, false, true).getProjectName());
return null;
}
});

// Login as user with access to testJob:
WebClient wc = createWebClient();
wc.login("joe", "joe");
wc.executeOnServer(new Callable<Object>() {
public Object call() throws Exception {
assertEquals("Should allow use of testJob for joe", "testJob",
new CopyArtifact("testJob", null, null, null, null, false, false, true).getProjectName());
return null;
// any users can be authenticated with the password same to the user id.
jenkins.setSecurityRealm(createDummySecurityRealm());
ProjectMatrixAuthorizationStrategy pmas = new ProjectMatrixAuthorizationStrategy();
pmas.add(Jenkins.READ, Jenkins.ANONYMOUS.getName());
pmas.add(Jenkins.READ, "joe");
jenkins.setAuthorizationStrategy(pmas);

// only joe can access project "src"
FreeStyleProject src = createFreeStyleProject();
{
Map<Permission, Set<String>> auths = new HashMap<Permission, Set<String>>();
auths.put(Item.READ, Sets.newHashSet("joe"));
src.addProperty(new AuthorizationMatrixProperty(auths));
}

// test access from anonymous
{
FreeStyleProject dest = createFreeStyleProject();
dest.getBuildersList().add(new CopyArtifact(
src.getName(),
"",
new StatusBuildSelector(true),
"",
"",
false,
false,
true
));
Map<Permission, Set<String>> auths = new HashMap<Permission, Set<String>>();
auths.put(Item.READ, Sets.newHashSet(Jenkins.ANONYMOUS.getName()));
auths.put(Item.CONFIGURE, Sets.newHashSet(Jenkins.ANONYMOUS.getName()));
dest.addProperty(new AuthorizationMatrixProperty(auths));

WebClient wc = createWebClient();
try {
wc.getPage(src);
fail("Job should not be accessible to anonymous");
} catch(FailingHttpStatusCodeException e) {
assertEquals("Job should not be accessible to anonymous", 404, e.getStatusCode());
}
});

submit(wc.getPage(dest, "configure").getFormByName("config"));

dest = jenkins.getItemByFullName(dest.getFullName(), FreeStyleProject.class);
CopyArtifact ca = dest.getBuildersList().getAll(CopyArtifact.class).get(0);
assertEquals("Should ignore/clear value for inaccessible project", "", ca.getProjectName());
}

// test access from joe
{
FreeStyleProject dest = createFreeStyleProject();
dest.getBuildersList().add(new CopyArtifact(
src.getName(),
"",
new StatusBuildSelector(true),
"",
"",
false,
false,
true
));
Map<Permission, Set<String>> auths = new HashMap<Permission, Set<String>>();
auths.put(Item.READ, Sets.newHashSet("joe"));
auths.put(Item.CONFIGURE, Sets.newHashSet("joe"));
dest.addProperty(new AuthorizationMatrixProperty(auths));

WebClient wc = createWebClient();
wc.login("joe", "joe");
assertNotNull(wc.getPage(src));

submit(wc.getPage(dest, "configure").getFormByName("config"));

dest = jenkins.getItemByFullName(dest.getFullName(), FreeStyleProject.class);
CopyArtifact ca = dest.getBuildersList().getAll(CopyArtifact.class).get(0);
assertEquals("Should ignore/clear value for inaccessible project", src.getName(), ca.getProjectName());
}
}

/**
Expand Down Expand Up @@ -1087,6 +1155,75 @@ public void testRelativeFromFolder() throws Exception {
assertFile(true, "foo.txt", b);
}

public void testSameFolder() throws Exception {
Folder folder = jenkins.createProject(Folder.class, "folder");
FreeStyleProject src = folder.createProject(FreeStyleProject.class, "src");
src.getBuildersList().add(new ArtifactBuilder());
src.getPublishersList().add(new ArtifactArchiver("**", "", false, false));
assertBuildStatusSuccess(src.scheduleBuild2(0));

FreeStyleProject dest = folder.createProject(FreeStyleProject.class, "dest");
dest.getBuildersList().add(new CopyArtifact(src.getName(), null, new StatusBuildSelector(true), "", "", false, false, true));
FreeStyleBuild b = dest.scheduleBuild2(0).get();
assertBuildStatusSuccess(b);
assertFile(true, "foo.txt", b);

WebClient wc = createWebClient();
submit(wc.getPage(dest, "configure").getFormByName("config"));

dest = jenkins.getItemByFullName(dest.getFullName(), FreeStyleProject.class);
CopyArtifact ca = (CopyArtifact)dest.getBuildersList().get(0);
assertEquals(src.getName(), ca.getProjectName());
}

public void testSameFolderFromMatrix() throws Exception {
Folder folder = jenkins.createProject(Folder.class, "folder");
MatrixProject src = folder.createProject(MatrixProject.class, "src");
src.setAxes(new AxisList(new TextAxis("axis1", "value1", "value2")));
src.getBuildersList().add(new ArtifactBuilder());
src.getPublishersList().add(new ArtifactArchiver("**", "", false, false));
assertBuildStatusSuccess(src.scheduleBuild2(0));

String projectNameToCopyFrom = String.format("%s/axis1=value1", src.getName());
FreeStyleProject dest = folder.createProject(FreeStyleProject.class, "dest");
dest.getBuildersList().add(new CopyArtifact(projectNameToCopyFrom, null, new StatusBuildSelector(true), "", "", false, false, true));
FreeStyleBuild b = dest.scheduleBuild2(0).get();
assertBuildStatusSuccess(b);
assertFile(true, "foo.txt", b);

WebClient wc = createWebClient();
submit(wc.getPage(dest, "configure").getFormByName("config"));

dest = jenkins.getItemByFullName(dest.getFullName(), FreeStyleProject.class);
CopyArtifact ca = (CopyArtifact)dest.getBuildersList().get(0);
assertEquals(projectNameToCopyFrom, ca.getProjectName());
}

@Bug(20940)
public void testSameFolderToMatrix() throws Exception {
Folder folder = jenkins.createProject(Folder.class, "foler");
FreeStyleProject src = folder.createProject(FreeStyleProject.class, "src");
src.getBuildersList().add(new ArtifactBuilder());
src.getPublishersList().add(new ArtifactArchiver("**", "", false, false));
assertBuildStatusSuccess(src.scheduleBuild2(0));

MatrixProject dest = folder.createProject(MatrixProject.class, "dest");
dest.setAxes(new AxisList(new TextAxis("axis1", "value1", "value2")));
dest.getBuildersList().add(new CopyArtifact(src.getName(), null, new StatusBuildSelector(true), "", "", false, false, true));
MatrixBuild b = dest.scheduleBuild2(0).get();
assertBuildStatusSuccess(b);
for(MatrixRun r: b.getExactRuns()) {
assertFile(true, "foo.txt", r);
}

WebClient wc = createWebClient();
submit(wc.getPage(dest, "configure").getFormByName("config"));

dest = jenkins.getItemByFullName(dest.getFullName(), MatrixProject.class);
CopyArtifact ca = (CopyArtifact)dest.getBuildersList().get(0);
assertEquals(src.getName(), ca.getProjectName());
}

@Test
@LocalData
public void testOldCopyArtifactConfigIsLoadedCorrectly() throws Exception {
Expand Down

0 comments on commit b33ceb5

Please sign in to comment.