@@ -27,6 +27,8 @@
import com .gargoylesoftware .htmlunit .html .HtmlForm ;
import com .gargoylesoftware .htmlunit .html .HtmlPage ;
import com .gargoylesoftware .htmlunit .html .HtmlTextArea ;
import com .gargoylesoftware .htmlunit .html .Util ;
import hudson .model .FreeStyleProject ;
import hudson .model .FreeStyleBuild ;
import hudson .model .Item ;
@@ -35,25 +37,36 @@
import hudson .security .Permission ;
import hudson .tasks .BuildStepDescriptor ;
import hudson .tasks .Publisher ;
import java .io .File ;
import java .net .URISyntaxException ;
import java .util .ArrayList ;
import java .util .List ;
import java .util .Set ;
import jenkins .model .Jenkins ;
import org .apache .commons .io .FileUtils ;
import org .apache .commons .lang .StringUtils ;
import org .apache .tools .ant .DirectoryScanner ;
import org .apache .tools .ant .taskdefs .Expand ;
import org .apache .tools .ant .taskdefs .Touch ;
import org .jenkinsci .plugins .scriptsecurity .scripts .ScriptApproval ;
import org .jenkinsci .plugins .scriptsecurity .scripts .UnapprovedUsageException ;
import static org .junit .Assert .*;
import org .junit .Rule ;
import org .junit .Test ;
import org .junit .rules .TemporaryFolder ;
import org .jvnet .hudson .test .JenkinsRule ;
public class SecureGroovyScriptTest {
@ Rule public JenkinsRule r = new JenkinsRule ();
@ Rule public TemporaryFolder tmpFolderRule = new TemporaryFolder ();
@ Test public void basicApproval () throws Exception {
r .jenkins .setSecurityRealm (r .createDummySecurityRealm ());
GlobalMatrixAuthorizationStrategy gmas = new GlobalMatrixAuthorizationStrategy ();
@@ -110,7 +123,7 @@ private List<File> getAllJarFiles() throws URISyntaxException {
DirectoryScanner ds = new DirectoryScanner ();
ds .setBasedir (testClassDir );
ds .setIncludes (new String []{ "**/* .jar" });
ds .setIncludes (new String []{ "*.jar" });
ds .scan ();
List <File > ret = new ArrayList <File >();
@@ -122,6 +135,26 @@ private List<File> getAllJarFiles() throws URISyntaxException {
return ret ;
}
private List <File > getAllUpdatedJarFiles () throws URISyntaxException {
String testClassPath = String .format (StringUtils .join (getClass ().getName ().split ("\\." ), "/" ));
File testClassDir = new File (ClassLoader .getSystemResource (testClassPath ).toURI ()).getAbsoluteFile ();
File updatedDir = new File (testClassDir , "updated" );
DirectoryScanner ds = new DirectoryScanner ();
ds .setBasedir (updatedDir );
ds .setIncludes (new String []{ "*.jar" });
ds .scan ();
List <File > ret = new ArrayList <File >();
for (String relpath : ds .getIncludedFiles ()) {
ret .add (new File (updatedDir , relpath ));
}
return ret ;
}
@ Test public void testClasspathConfiguration () throws Exception {
List <AdditionalClasspath > classpathList = new ArrayList <AdditionalClasspath >();
for (File jarfile : getAllJarFiles ()) {
@@ -303,4 +336,273 @@ private List<File> getAllJarFiles() throws URISyntaxException {
r .assertBuildStatusSuccess (p .scheduleBuild2 (0 ));
}
}
@ Test public void testUpdatedClasspath () throws Exception {
r .jenkins .setSecurityRealm (r .createDummySecurityRealm ());
GlobalMatrixAuthorizationStrategy gmas = new GlobalMatrixAuthorizationStrategy ();
gmas .add (Jenkins .READ , "devel" );
for (Permission p : Item .PERMISSIONS .getPermissions ()) {
gmas .add (p , "devel" );
}
r .jenkins .setAuthorizationStrategy (gmas );
// Copy jar files to temporary directory, then overwrite them with updated jar files.
File tmpDir = tmpFolderRule .newFolder ();
for (File jarfile : getAllJarFiles ()) {
FileUtils .copyFileToDirectory (jarfile , tmpDir );
}
List <AdditionalClasspath > classpathList = new ArrayList <AdditionalClasspath >();
for (File jarfile : tmpDir .listFiles ()) {
classpathList .add (new AdditionalClasspath (jarfile .getAbsolutePath ()));
}
String SCRIPT_TO_RUN = "\"Script is run\";" ;
// approve script
{
FreeStyleProject p = r .createFreeStyleProject ();
p .getPublishersList ().add (new TestGroovyRecorder (new SecureGroovyScript (SCRIPT_TO_RUN , false )));
Set <ScriptApproval .PendingScript > pss = ScriptApproval .get ().getPendingScripts ();
assertNotEquals (0 , pss .size ());
for (ScriptApproval .PendingScript ps : pss ) {
ScriptApproval .get ().approveScript (ps .getHash ());
}
}
// Success without classpaths
{
FreeStyleProject p = r .createFreeStyleProject ();
p .getPublishersList ().add (new TestGroovyRecorder (new SecureGroovyScript (SCRIPT_TO_RUN , false )));
r .assertBuildStatusSuccess (p .scheduleBuild2 (0 ).get ());
}
FreeStyleProject p = r .createFreeStyleProject ();
p .getPublishersList ().add (new TestGroovyRecorder (new SecureGroovyScript (SCRIPT_TO_RUN , false , classpathList )));
// Fail as the classpath is not approved.
r .assertBuildStatus (Result .FAILURE , p .scheduleBuild2 (0 ).get ());
// Approve classpath.
{
List <ScriptApproval .PendingClasspath > pcps = ScriptApproval .get ().getPendingClasspaths ();
assertNotEquals (0 , pcps .size ());
for (ScriptApproval .PendingClasspath pcp : pcps ) {
ScriptApproval .get ().approveClasspath (pcp .getHash (), pcp .getPath ());
}
}
// Success as approved.
r .assertBuildStatusSuccess (p .scheduleBuild2 (0 ));
// overwrite jar files.
for (File jarfile : getAllUpdatedJarFiles ()) {
FileUtils .copyFileToDirectory (jarfile , tmpDir );
}
// Fail as the updated jar files are not approved.
r .assertBuildStatus (Result .FAILURE , p .scheduleBuild2 (0 ).get ());
// Approve classpath.
{
List <ScriptApproval .PendingClasspath > pcps = ScriptApproval .get ().getPendingClasspaths ();
assertNotEquals (0 , pcps .size ());
for (ScriptApproval .PendingClasspath pcp : pcps ) {
ScriptApproval .get ().approveClasspath (pcp .getHash (), pcp .getPath ());
}
}
// Success as approved.
r .assertBuildStatusSuccess (p .scheduleBuild2 (0 ));
}
@ Test public void testClasspathWithClassDirectory () throws Exception {
r .jenkins .setSecurityRealm (r .createDummySecurityRealm ());
GlobalMatrixAuthorizationStrategy gmas = new GlobalMatrixAuthorizationStrategy ();
gmas .add (Jenkins .READ , "devel" );
for (Permission p : Item .PERMISSIONS .getPermissions ()) {
gmas .add (p , "devel" );
}
r .jenkins .setAuthorizationStrategy (gmas );
// Copy jar files to temporary directory, then overwrite them with updated jar files.
File tmpDir = tmpFolderRule .newFolder ();
for (File jarfile : getAllJarFiles ()) {
Expand e = new Expand ();
e .setSrc (jarfile );
e .setDest (tmpDir );
e .execute ();
}
List <AdditionalClasspath > classpathList = new ArrayList <AdditionalClasspath >();
classpathList .add (new AdditionalClasspath (tmpDir .getAbsolutePath ()));
final String testingDisplayName = "TESTDISPLAYNAME" ;
FreeStyleProject p = r .createFreeStyleProject ();
p .getPublishersList ().add (new TestGroovyRecorder (new SecureGroovyScript (
String .format (
"import org.jenkinsci.plugins.scriptsecurity.testjar.BuildUtil;"
+ "BuildUtil.setDisplayNameWhitelisted(build, \"%s\");"
+ "\"\"" , testingDisplayName ),
true ,
classpathList
)));
// Fail as the classpath is not approved.
{
FreeStyleBuild b = p .scheduleBuild2 (0 ).get ();
r .assertBuildStatus (Result .FAILURE , b );
assertNotEquals (testingDisplayName , b .getDisplayName ());
}
// Approve classpath.
{
List <ScriptApproval .PendingClasspath > pcps = ScriptApproval .get ().getPendingClasspaths ();
assertNotEquals (0 , pcps .size ());
for (ScriptApproval .PendingClasspath pcp : pcps ) {
ScriptApproval .get ().approveClasspath (pcp .getHash (), pcp .getPath ());
}
}
// Success as approved.
{
FreeStyleBuild b = p .scheduleBuild2 (0 ).get ();
r .assertBuildStatusSuccess (b );
assertEquals (testingDisplayName , b .getDisplayName ());
}
// add new file in tmpDir.
{
File f = tmpFolderRule .newFile ();
FileUtils .copyFileToDirectory (f , tmpDir );
}
// Fail as the class directory is updated.
{
FreeStyleBuild b = p .scheduleBuild2 (0 ).get ();
r .assertBuildStatus (Result .FAILURE , b );
assertNotEquals (testingDisplayName , b .getDisplayName ());
}
// Approve classpath.
{
List <ScriptApproval .PendingClasspath > pcps = ScriptApproval .get ().getPendingClasspaths ();
assertNotEquals (0 , pcps .size ());
for (ScriptApproval .PendingClasspath pcp : pcps ) {
ScriptApproval .get ().approveClasspath (pcp .getHash (), pcp .getPath ());
}
}
// Success as approved.
{
FreeStyleBuild b = p .scheduleBuild2 (0 ).get ();
r .assertBuildStatusSuccess (b );
assertEquals (testingDisplayName , b .getDisplayName ());
}
}
@ Test public void testDifferentClasspathButSameContent () throws Exception {
r .jenkins .setSecurityRealm (r .createDummySecurityRealm ());
GlobalMatrixAuthorizationStrategy gmas = new GlobalMatrixAuthorizationStrategy ();
gmas .add (Jenkins .READ , "devel" );
for (Permission p : Item .PERMISSIONS .getPermissions ()) {
gmas .add (p , "devel" );
}
r .jenkins .setAuthorizationStrategy (gmas );
final String testingDisplayName = "TESTDISPLAYNAME" ;
File tmpDir1 = tmpFolderRule .newFolder ();
for (File jarfile : getAllJarFiles ()) {
Expand e = new Expand ();
e .setSrc (jarfile );
e .setDest (tmpDir1 );
e .execute ();
}
List <AdditionalClasspath > classpathList1 = new ArrayList <AdditionalClasspath >();
classpathList1 .add (new AdditionalClasspath (tmpDir1 .getAbsolutePath ()));
FreeStyleProject p1 = r .createFreeStyleProject ();
p1 .getPublishersList ().add (new TestGroovyRecorder (new SecureGroovyScript (
String .format (
"import org.jenkinsci.plugins.scriptsecurity.testjar.BuildUtil;"
+ "BuildUtil.setDisplayNameWhitelisted(build, \"%s\");"
+ "\"\"" , testingDisplayName ),
true ,
classpathList1
)));
// Fail as the classpath is not approved.
{
FreeStyleBuild b = p1 .scheduleBuild2 (0 ).get ();
r .assertBuildStatus (Result .FAILURE , b );
assertNotEquals (testingDisplayName , b .getDisplayName ());
}
// Approve classpath.
{
List <ScriptApproval .PendingClasspath > pcps = ScriptApproval .get ().getPendingClasspaths ();
assertNotEquals (0 , pcps .size ());
for (ScriptApproval .PendingClasspath pcp : pcps ) {
ScriptApproval .get ().approveClasspath (pcp .getHash (), pcp .getPath ());
}
}
// Success as approved.
{
FreeStyleBuild b = p1 .scheduleBuild2 (0 ).get ();
r .assertBuildStatusSuccess (b );
assertEquals (testingDisplayName , b .getDisplayName ());
}
File tmpDir2 = tmpFolderRule .newFolder ();
for (File jarfile : getAllJarFiles ()) {
Expand e = new Expand ();
e .setSrc (jarfile );
e .setDest (tmpDir2 );
e .execute ();
}
// touch all files.
{
DirectoryScanner ds = new DirectoryScanner ();
ds .setBasedir (tmpDir2 );
ds .setIncludes (new String []{ "**" });
ds .scan ();
for (String relpath : ds .getIncludedFiles ()) {
Touch t = new Touch ();
t .setFile (new File (tmpDir2 , relpath ));
t .execute ();
}
}
List <AdditionalClasspath > classpathList2 = new ArrayList <AdditionalClasspath >();
classpathList2 .add (new AdditionalClasspath (tmpDir2 .getAbsolutePath ()));
FreeStyleProject p2 = r .createFreeStyleProject ();
p2 .getPublishersList ().add (new TestGroovyRecorder (new SecureGroovyScript (
String .format (
"import org.jenkinsci.plugins.scriptsecurity.testjar.BuildUtil;"
+ "BuildUtil.setDisplayNameWhitelisted(build, \"%s\");"
+ "\"\"" , testingDisplayName ),
true ,
classpathList2
)));
// Success as approved.
{
FreeStyleBuild b = p2 .scheduleBuild2 (0 ).get ();
r .assertBuildStatusSuccess (b );
assertEquals (testingDisplayName , b .getDisplayName ());
}
}
}