All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.h3xstream.maven.SecurityVersionsCheck Maven / Gradle / Ivy

The newest version!
package com.h3xstream.maven;

import com.h3xstream.maven.tpl.ProjectSummary;
import com.h3xstream.maven.tpl.VulnerableLibrary;
import com.h3xstream.maven.victims.CveVulnerability;
import com.h3xstream.maven.victims.VictimsDbLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.manager.WagonConfigurationException;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
import org.apache.maven.shared.dependency.graph.DependencyNode;
import org.apache.maven.wagon.ConnectionException;
import org.apache.maven.wagon.UnsupportedProtocolException;
import org.apache.maven.wagon.authentication.AuthenticationException;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 *
 * @goal check
 * @requiresProject true
 * @requiresDirectInvocation false
 * @aggregator true
 */
public class SecurityVersionsCheck extends AbstractMojo {

    /**
     * @parameter property="sec.updateRepo" defaultValue="false"
     */
    private Boolean updateRepository = Boolean.FALSE;
    private static VictimsDbLoader victimDb;
    private static Object victimDbSync = new Object();

    public void execute() throws MojoExecutionException, MojoFailureException {

        MavenProject rootProject = getProject();

        if(!rootProject.isExecutionRoot()) {
            return;
        }

        //Only execute this mojo once, on the very last project in the reactor
        if(reactorProjects != null) {
            final int size = reactorProjects.size();
            MavenProject lastProject = (MavenProject) reactorProjects.get(size - 1);
            if (lastProject != getProject()) {
                return;
            }
        }

        List projectSummaries = new ArrayList();

        try {
            //The plugin will scan will include all submodules + the current projects.
            List allProjects = new ArrayList(rootProject.getCollectedProjects());
            allProjects.add(rootProject);

            for(MavenProject project : allProjects) {
                getLog().info("Analyzing the dependencies for " + project.getGroupId() + ":" + project.getArtifactId());

                synchronized (victimDbSync) {
                    if (victimDb == null) {
                        victimDb = new VictimsDbLoader(getLog(), wagonManager);
                        victimDb.loadRepository();
                    }
                }


                DependencyNode rootNode;
                try {
                    rootNode = dependencyGraphBuilder.buildDependencyGraph(project, createResolvingArtifactFilter());

                } catch (DependencyGraphBuilderException e) {
                    getLog().error("Unable to build the complete dependency graph.");
                    throw new MojoFailureException("Unable to build the complete dependency graph.", e);
                }

                //Collect the vulnerabilities
                List vulnerableLibraries = new ArrayList();
                visitNode(rootNode, 0, vulnerableLibraries);

                //Output the vulnerabilities found
                displayCommandLine(vulnerableLibraries);

                if(vulnerableLibraries.size() > 0) {
                    projectSummaries.add(new ProjectSummary(project, vulnerableLibraries));
                }

            }

        } catch (WagonConfigurationException e) {
            throw new MojoFailureException("Unable load the repository.", e);
        } catch (UnsupportedProtocolException e) {
            throw new MojoFailureException("Unable load the repository.", e);
        } catch (ConnectionException e) {
            throw new MojoFailureException("Unable load the repository.", e);
        } catch (AuthenticationException e) {
            throw new MojoFailureException("Unable load the repository.", e);
        }


        try {
            File targetDir = new File(getProject().getBuild().getDirectory());
            if (!targetDir.exists()) targetDir.mkdir();

            new File(targetDir, "/dependencies/").mkdir();

            FileOutputStream out = new FileOutputStream(new File(targetDir, "/dependencies/index.html"));

            for(String file : Arrays.asList("bootstrap.min.css","font-awesome.min.css","fontawesome-webfont.ttf")) {
                copy(getClass().getResourceAsStream("/victims_tpl/"+file), new FileOutputStream(new File(targetDir, "/dependencies/"+file)));
            }

            exportToHtml(projectSummaries, out);

        } catch (FileNotFoundException e) {
            throw new MojoFailureException("Unable to write the HTML report.", e);
        } catch (IOException e) {
            throw new MojoFailureException("Unable to write the HTML report.", e);
        } catch (TemplateException e) {
            throw new MojoFailureException("Unable generate the HTML report using the template.", e);
        }

    }

    private void visitNode(DependencyNode baseNode,int level,List vulnerabilities) {
        Artifact a = baseNode.getArtifact();

        //getLog().info(StringUtils.repeat("   ",level)+" -> "+a.getGroupId()+":"+a.getArtifactId()+":"+a.getVersion());

        List cves = victimDb.search(a.getGroupId(), a.getArtifactId(), a.getVersion());

        if(cves.size() > 0) {
            vulnerabilities.add(new VulnerableLibrary(a, cves, getHierarchyChain(baseNode)));
        }

        for (DependencyNode childNode : baseNode.getChildren()) {
            visitNode(childNode, level + 1, vulnerabilities);
        }
    }

    private List getHierarchyChain(DependencyNode baseNode) {
        List chain = new ArrayList();

        DependencyNode node = baseNode;
        while((node = node.getParent()) != null) {
            chain.add(node.getArtifact());
        }
        return chain;
    }

    public void displayCommandLine(List libraries) {
        if(!libraries.isEmpty()) {
            for(VulnerableLibrary lib : libraries) {
                Artifact a = lib.getArtifact();
                for(CveVulnerability vuln : lib.getVulnerabilities()) {
                    getLog().error(a.getGroupId() + ":" + a.getArtifactId() + " is vulnerable to CVE-" + vuln.getCveId());
                }
            }
        }
    }

    public void exportToHtml(List projects,OutputStream out) throws IOException, TemplateException {
        PrintWriter pw = new PrintWriter(out);

        //FreeMarker Template
        Configuration cfg = new Configuration();
        cfg.setClassForTemplateLoading(this.getClass(), "/");
        Template tpl = cfg.getTemplate("/victims_tpl/vulnerable_dependencies.html");

        Map ctxData = new HashMap();
        ctxData.put("projects",projects);

        tpl.process(ctxData, new OutputStreamWriter(out));
    }

    /**
     * Gets the artifact filter to use when resolving the dependency tree.
     *
     * @return the artifact filter
     */
    private ArtifactFilter createResolvingArtifactFilter()
    {
        return new ArtifactFilter() {
            @Override
            public boolean include(Artifact artifact) {
                return true;
            }
        };
    }


    public void copy(InputStream in, OutputStream out) throws IOException {
        try {
            try {
                // Transfer bytes from in to out
                byte[] buf = new byte[1024];
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
            } finally {
                out.close();
            }
        } finally {
            in.close();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy