/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.gradle.plugins.defaults.internal; import com.liferay.gradle.plugins.defaults.internal.util.FileUtil; import com.liferay.gradle.plugins.defaults.internal.util.GradleUtil; import com.liferay.gradle.plugins.defaults.tasks.WriteFindBugsProjectTask; import com.liferay.gradle.plugins.jasper.jspc.CompileJSPTask; import com.liferay.gradle.plugins.jasper.jspc.JspCPlugin; import java.io.File; import java.util.Set; import java.util.concurrent.Callable; import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.Transformer; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.DependencySet; import org.gradle.api.file.FileCollection; import org.gradle.api.file.SourceDirectorySet; import org.gradle.api.logging.Logger; import org.gradle.api.plugins.JavaBasePlugin; import org.gradle.api.reporting.ReportingExtension; import org.gradle.api.specs.Spec; import org.gradle.api.tasks.JavaExec; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetOutput; import org.gradle.api.tasks.compile.JavaCompile; import org.gradle.language.base.plugins.LifecycleBasePlugin; /** * @author Andrea Di Giorgi */ public class FindSecurityBugsPlugin implements Plugin<Project> { public static final String FIND_SECURITY_BUGS_CONFIGURATION_NAME = "findSecurityBugs"; public static final String FIND_SECURITY_BUGS_PLUGINS_CONFIGURATION_NAME = "findSecurityBugsPlugins"; public static final String FIND_SECURITY_BUGS_TASK_NAME = "findSecurityBugs"; public static final Plugin<Project> INSTANCE = new FindSecurityBugsPlugin(); public static final String WRITE_FIND_BUGS_PROJECT_TASK_NAME = "writeFindBugsProject"; @Override public void apply(Project project) { Configuration findSecurityBugsConfiguration = _addConfigurationFindSecurityBugs(project); Configuration findSecurityBugsPluginsConfiguration = _addConfigurationFindSecurityBugsPlugins(project); WriteFindBugsProjectTask writeFindBugsProjectTask = _addTaskWriteFindBugsProject(project); Task findSecurityBugsTask = _addTaskFindSecurityBugs( writeFindBugsProjectTask, findSecurityBugsConfiguration, findSecurityBugsPluginsConfiguration); _checkTaskCheck(findSecurityBugsTask); } private FindSecurityBugsPlugin() { } private Configuration _addConfigurationFindSecurityBugs( final Project project) { Configuration configuration = GradleUtil.addConfiguration( project, FIND_SECURITY_BUGS_CONFIGURATION_NAME); configuration.defaultDependencies( new Action<DependencySet>() { @Override public void execute(DependencySet dependencySet) { _addDependenciesFindSecurityBugs(project); } }); configuration.setDescription( "Configures FindBugs for the '" + FIND_SECURITY_BUGS_TASK_NAME + "' task."); configuration.setVisible(false); return configuration; } private Configuration _addConfigurationFindSecurityBugsPlugins( final Project project) { Configuration configuration = GradleUtil.addConfiguration( project, FIND_SECURITY_BUGS_PLUGINS_CONFIGURATION_NAME); configuration.defaultDependencies( new Action<DependencySet>() { @Override public void execute(DependencySet dependencySet) { _addDependenciesFindSecurityBugsPlugins(project); } }); configuration.setDescription("Configures FindSecurityBugs."); configuration.setVisible(false); return configuration; } private void _addDependenciesFindSecurityBugs(Project project) { GradleUtil.addDependency( project, FIND_SECURITY_BUGS_CONFIGURATION_NAME, "com.google.code.findbugs", "findbugs", "3.0.1"); } private void _addDependenciesFindSecurityBugsPlugins(Project project) { GradleUtil.addDependency( project, FIND_SECURITY_BUGS_PLUGINS_CONFIGURATION_NAME, "com.liferay", "com.h3xstream.findsecbugs", _VERSION); } private JavaExec _addTaskFindSecurityBugs( final WriteFindBugsProjectTask writeFindBugsProjectTask, FileCollection classpath, final FileCollection pluginClasspath) { Project project = writeFindBugsProjectTask.getProject(); JavaExec javaExec = GradleUtil.addTask( project, FIND_SECURITY_BUGS_TASK_NAME, JavaExec.class); javaExec.args( "-bugCategories", "SECURITY", "-effort:max", "-html", "-low", "-progress", "-timestampNow"); File excludeDir = GradleUtil.getRootDir( project, _FIND_SECURITY_BUGS_EXCLUDE_FILE_NAME); if (excludeDir != null) { File excludeFile = new File( excludeDir, _FIND_SECURITY_BUGS_EXCLUDE_FILE_NAME); javaExec.args("-exclude", FileUtil.getAbsolutePath(excludeFile)); } File includeDir = GradleUtil.getRootDir( project, _FIND_SECURITY_BUGS_INCLUDE_FILE_NAME); if (includeDir != null) { File includeFile = new File( includeDir, _FIND_SECURITY_BUGS_INCLUDE_FILE_NAME); javaExec.args("-include", FileUtil.getAbsolutePath(includeFile)); } javaExec.args( "-project", new Object() { @Override public String toString() { return FileUtil.getAbsolutePath( writeFindBugsProjectTask.getOutputFile()); } }); final Transformer<File, Task> outputFileGetter = new Transformer<File, Task>() { @Override public File transform(Task task) { ReportingExtension reportingExtension = GradleUtil.getExtension( task.getProject(), ReportingExtension.class); return new File( reportingExtension.getBaseDir(), task.getName() + "/reports.html"); } }; javaExec.doFirst( new Action<Task>() { @Override public void execute(Task task) { JavaExec javaExec = (JavaExec)task; Logger logger = javaExec.getLogger(); File outputFile = outputFileGetter.transform(javaExec); File outputDir = outputFile.getParentFile(); outputDir.mkdirs(); javaExec.args( "-outputFile", FileUtil.getAbsolutePath(outputFile)); javaExec.args("-pluginList", pluginClasspath.getAsPath()); if (logger.isLifecycleEnabled()) { logger.lifecycle( "Using Find Security Bugs version " + _VERSION); } } }); javaExec.doLast( new Action<Task>() { @Override public void execute(Task task) { Logger logger = task.getLogger(); File outputFile = outputFileGetter.transform(task); if (logger.isLifecycleEnabled()) { logger.lifecycle( "Find Security Bugs report saved to {}.", outputFile.getAbsolutePath()); } } }); javaExec.dependsOn(writeFindBugsProjectTask); javaExec.onlyIf( new Spec<Task>() { @Override public boolean isSatisfiedBy(Task task) { FileCollection fileCollection = writeFindBugsProjectTask.getClasspath(); if (fileCollection == null) { return true; } Set<File> files = fileCollection.getFiles(); return _containsClassOrJar( files.toArray(new File[files.size()])); } private boolean _containsClassOrJar(File[] files) { for (File file : files) { if (!file.exists()) { continue; } if (file.isFile()) { String fileName = file.getName(); if (fileName.endsWith(".class") || fileName.endsWith(".jar")) { return true; } } else if (_containsClassOrJar(file.listFiles())) { return true; } } return false; } }); javaExec.setClasspath(classpath); javaExec.setDescription("Runs FindSecurityBugs on this project."); javaExec.setGroup(JavaBasePlugin.VERIFICATION_GROUP); javaExec.setMain("edu.umd.cs.findbugs.FindBugs2"); javaExec.systemProperty( "findsecbugs.injection.customconfigfile.SqlInjectionDetector", "liferay-config/liferay-SqlInjectionDetector.txt|" + "SQL_INJECTION_HIBERNATE"); javaExec.systemProperty( "findsecbugs.injection.customconfigfile.XssJspDetector", "liferay-config/liferay-XssJspDetector.txt|XSS_JSP_PRINT"); javaExec.systemProperty("findsecbugs.taint.outputsummaries", "true"); String customConfigFile = "liferay-config/liferay.txt"; File derivedSummariesTxtFile = project.file("derived-summaries.txt"); if (derivedSummariesTxtFile.exists()) { customConfigFile = customConfigFile + ":" + FileUtil.getAbsolutePath(derivedSummariesTxtFile); } File falsePositivesTxtFile = project.file( "find-security-bugs-false-positives.txt"); if (falsePositivesTxtFile.exists()) { customConfigFile = customConfigFile + ":" + FileUtil.getAbsolutePath(falsePositivesTxtFile); } javaExec.systemProperty( "findsecbugs.taint.customconfigfile", customConfigFile); return javaExec; } private WriteFindBugsProjectTask _addTaskWriteFindBugsProject( final Project project) { WriteFindBugsProjectTask writeFindBugsProjectTask = GradleUtil.addTask( project, WRITE_FIND_BUGS_PROJECT_TASK_NAME, WriteFindBugsProjectTask.class); JavaCompile compileJSPTask = (JavaCompile)GradleUtil.getTask( project, JspCPlugin.COMPILE_JSP_TASK_NAME); writeFindBugsProjectTask.dependsOn( _UNZIP_JAR_TASK_NAME, compileJSPTask); final SourceSet sourceSet = GradleUtil.getSourceSet( project, SourceSet.MAIN_SOURCE_SET_NAME); FileCollection auxClasspath = project.files( sourceSet.getCompileClasspath(), compileJSPTask.getClasspath()); writeFindBugsProjectTask.setAuxClasspath(auxClasspath); FileCollection classpath = project.files( compileJSPTask.getDestinationDir(), new Callable<File>() { @Override public File call() throws Exception { SourceSetOutput sourceSetOutput = sourceSet.getOutput(); return sourceSetOutput.getClassesDir(); } }); writeFindBugsProjectTask.setClasspath(classpath); writeFindBugsProjectTask.setDescription( "Writes the FindBugs project file."); writeFindBugsProjectTask.setOutputFile( new Callable<File>() { @Override public File call() throws Exception { return new File(project.getBuildDir(), "findbugs.xml"); } }); writeFindBugsProjectTask.setProjectName(project.getName()); CompileJSPTask generateJSPJavaTask = (CompileJSPTask)GradleUtil.getTask( project, JspCPlugin.GENERATE_JSP_JAVA_TASK_NAME); SourceDirectorySet sourceDirectorySet = sourceSet.getJava(); FileCollection srcDirs = project.files( sourceDirectorySet.getSrcDirs(), generateJSPJavaTask.getDestinationDir()); writeFindBugsProjectTask.setSrcDirs(srcDirs); return writeFindBugsProjectTask; } private void _checkTaskCheck(Task findSecurityBugsTask) { Task task = GradleUtil.getTask( findSecurityBugsTask.getProject(), LifecycleBasePlugin.CHECK_TASK_NAME); task.dependsOn(findSecurityBugsTask); } private static final String _FIND_SECURITY_BUGS_EXCLUDE_FILE_NAME = "fsb-exclude.xml"; private static final String _FIND_SECURITY_BUGS_INCLUDE_FILE_NAME = "fsb-include.xml"; /** * Copied from <code>com.liferay.gradle.plugins.internal.JspCDefaultsPlugin</code>. */ private static final String _UNZIP_JAR_TASK_NAME = "unzipJar"; private static final String _VERSION = "1.6.0.LIFERAY-PATCHED-2"; }