|
51 | 51 | import org.junit.Test;
|
52 | 52 | import static org.junit.Assert.*;
|
53 | 53 | import org.junit.ClassRule;
|
| 54 | +import org.junit.Ignore; |
54 | 55 | import org.junit.Rule;
|
55 | 56 | import org.jvnet.hudson.test.BuildWatcher;
|
56 | 57 | import org.jvnet.hudson.test.Issue;
|
@@ -124,6 +125,99 @@ public class LibraryStepTest {
|
124 | 125 | r.assertLogContains("using constant vs. constant", b);
|
125 | 126 | }
|
126 | 127 |
|
| 128 | + @Test public void missingProperty() throws Exception { |
| 129 | + sampleRepo.init(); |
| 130 | + sampleRepo.write("src/some/pkg/MyClass.groovy", "package some.pkg; class MyClass { }"); |
| 131 | + sampleRepo.git("add", "src"); |
| 132 | + sampleRepo.git("commit", "--message=init"); |
| 133 | + Folder f = r.jenkins.createProject(Folder.class, "f"); |
| 134 | + f.getProperties().add(new FolderLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true)))))); |
| 135 | + WorkflowJob p = f.createProject(WorkflowJob.class, "p"); |
| 136 | + p.setDefinition(new CpsFlowDefinition( |
| 137 | + "def lib = library 'stuff@master'\n" + |
| 138 | + "lib.some.pkg.MyClass.no_field_with_this_name\n" , true)); |
| 139 | + WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); |
| 140 | + r.assertLogContains("MissingPropertyException: No such property: no_field_with_this_name for class: some.pkg.MyClass", b); |
| 141 | + } |
| 142 | + |
| 143 | + @Test public void reflectionInLoadedClassesIsIntercepted() throws Exception { |
| 144 | + sampleRepo.init(); |
| 145 | + sampleRepo.write("src/some/pkg/MyThread.groovy", "package some.pkg; class MyThread extends Thread { }"); |
| 146 | + sampleRepo.git("add", "src"); |
| 147 | + sampleRepo.git("commit", "--message=init"); |
| 148 | + Folder f = r.jenkins.createProject(Folder.class, "f"); |
| 149 | + f.getProperties().add(new FolderLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true)))))); |
| 150 | + WorkflowJob p = f.createProject(WorkflowJob.class, "p"); |
| 151 | + p.setDefinition(new CpsFlowDefinition( |
| 152 | + "def lib = library 'stuff@master'\n" + |
| 153 | + "catchError() { lib.some.pkg.MyThread.new(null) }\n" + |
| 154 | + "catchError() { lib.some.pkg.MyThread.__$stMC }\n" + |
| 155 | + "catchError() { lib.some.pkg.MyThread.$getCallSiteArray() }\n" , true)); |
| 156 | + WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); |
| 157 | + r.assertLogContains("Rejecting illegal call to synthetic constructor", b); |
| 158 | + r.assertLogContains("staticField some.pkg.MyThread __$stMC", b); |
| 159 | + r.assertLogContains("staticMethod some.pkg.MyThread $getCallSiteArray", b); |
| 160 | + } |
| 161 | + |
| 162 | + @Issue("SECURITY-2824") |
| 163 | + @Test public void constructorInvocationInLoadedClassesIsIntercepted() throws Exception { |
| 164 | + sampleRepo.init(); |
| 165 | + sampleRepo.write("src/pkg/Superclass.groovy", |
| 166 | + "package pkg;\n" + |
| 167 | + "class Superclass { Superclass(String x) { } }\n"); |
| 168 | + sampleRepo.write("src/pkg/Subclass.groovy", |
| 169 | + "package pkg;\n" + |
| 170 | + "class Subclass extends Superclass {\n" + |
| 171 | + " def wrapper\n" + |
| 172 | + " Subclass() { super('secret.key'); def $cw = $cw; wrapper = $cw }\n" + |
| 173 | + "}\n"); |
| 174 | + sampleRepo.write("src/pkg/MyFile.groovy", |
| 175 | + "package pkg;\n" + |
| 176 | + "class MyFile extends File {\n" + |
| 177 | + " MyFile(String path) {\n" + |
| 178 | + " super(path)\n" + |
| 179 | + " }\n" + |
| 180 | + "}\n"); |
| 181 | + sampleRepo.git("add", "src"); |
| 182 | + sampleRepo.git("commit", "--message=init"); |
| 183 | + Folder f = r.jenkins.createProject(Folder.class, "f"); |
| 184 | + f.getProperties().add(new FolderLibraries(Collections.singletonList(new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true)))))); |
| 185 | + WorkflowJob p = f.createProject(WorkflowJob.class, "p"); |
| 186 | + p.setDefinition(new CpsFlowDefinition( |
| 187 | + "def lib = library 'stuff@master'\n" + |
| 188 | + "def wrapper = lib.pkg.Subclass.new().wrapper\n" + |
| 189 | + "def file = lib.pkg.MyFile.new(wrapper, 'unused')\n" + |
| 190 | + "echo(/${[file, file.class]}/)", true)); |
| 191 | + WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); |
| 192 | + r.assertLogContains("Rejecting illegal call to synthetic constructor: private pkg.MyFile", b); |
| 193 | + } |
| 194 | + |
| 195 | + @Ignore("Trusted libraries should never get a RejectedAccessException, but this case should be uncommon and is difficult to handle more precisely") |
| 196 | + @Test public void falsePositiveRejectedAccessExceptionInTrustedLibrary() throws Exception { |
| 197 | + sampleRepo.init(); |
| 198 | + sampleRepo.git("branch", "myBranch"); |
| 199 | + sampleRepo.write("vars/doStuff.groovy", |
| 200 | + "def call() {\n" + |
| 201 | + " def lib = library('stuff2@myBranch')\n" + |
| 202 | + " lib.some.pkg.MyClass.$getCallSiteArray()\n" + |
| 203 | + "}\n"); |
| 204 | + sampleRepo.git("add", "."); |
| 205 | + sampleRepo.git("commit", "--message=init"); |
| 206 | + sampleRepo.git("checkout", "myBranch"); |
| 207 | + sampleRepo.write("src/some/pkg/MyClass.groovy", "package some.pkg; class MyClass { }"); |
| 208 | + sampleRepo.git("add", "."); |
| 209 | + sampleRepo.git("commit", "--message=myBranch"); |
| 210 | + GlobalLibraries.get().setLibraries(Arrays.asList( |
| 211 | + new LibraryConfiguration("stuff", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))), |
| 212 | + new LibraryConfiguration("stuff2", new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true))))); |
| 213 | + WorkflowJob p = r.createProject(WorkflowJob.class, "p"); |
| 214 | + p.setDefinition(new CpsFlowDefinition( |
| 215 | + "@Library('stuff@master')\n" + |
| 216 | + "import doStuff\n" + |
| 217 | + "doStuff()\n", true)); |
| 218 | + WorkflowRun b = r.buildAndAssertSuccess(p); |
| 219 | + } |
| 220 | + |
127 | 221 | @Test public void classesFromWrongPlace() throws Exception {
|
128 | 222 | sampleRepo.init();
|
129 | 223 | sampleRepo.write("src/some/pkg/Lib.groovy", "package some.pkg; class Lib {static void m() {}}");
|
|
0 commit comments