View Javadoc
1   /**
2    * Portions of this software was developed by employees of the National Institute
3    * of Standards and Technology (NIST), an agency of the Federal Government and is
4    * being made available as a public service. Pursuant to title 17 United States
5    * Code Section 105, works of NIST employees are not subject to copyright
6    * protection in the United States. This software may be subject to foreign
7    * copyright. Permission in the United States and in foreign countries, to the
8    * extent that NIST may hold copyright, to use, copy, modify, create derivative
9    * works, and distribute this software and its documentation without fee is hereby
10   * granted on a non-exclusive basis, provided that this notice and disclaimer
11   * of warranty appears in all copies.
12   *
13   * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
14   * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
15   * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
17   * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
18   * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
19   * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
20   * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
21   * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
22   * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
23   * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
24   * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
25   */
26  
27  package gov.nist.secauto.swid.plugin;
28  
29  import gov.nist.secauto.swid.builder.SWIDBuilder;
30  import gov.nist.secauto.swid.builder.ValidationException;
31  import gov.nist.secauto.swid.builder.output.XMLOutputHandler;
32  import gov.nist.secauto.swid.plugin.entry.FileEntry;
33  import gov.nist.secauto.swid.plugin.entry.archive.ArchiveEntryFileEntryProcessor;
34  import gov.nist.secauto.swid.plugin.generate.MavenProjectSwidBuilderHelper;
35  import gov.nist.secauto.swid.plugin.model.Entity;
36  
37  import org.apache.maven.monitor.logging.DefaultLog;
38  import org.apache.maven.plugin.logging.Log;
39  import org.apache.maven.plugins.annotations.Parameter;
40  import org.apache.maven.plugins.assembly.filter.ContainerDescriptorHandler;
41  import org.apache.maven.project.MavenProject;
42  import org.codehaus.plexus.archiver.ArchiveEntry;
43  import org.codehaus.plexus.archiver.Archiver;
44  import org.codehaus.plexus.archiver.ArchiverException;
45  import org.codehaus.plexus.archiver.UnArchiver;
46  import org.codehaus.plexus.component.annotations.Component;
47  import org.codehaus.plexus.component.annotations.Requirement;
48  import org.codehaus.plexus.components.io.fileselectors.FileInfo;
49  import org.codehaus.plexus.logging.Logger;
50  
51  import java.io.BufferedOutputStream;
52  import java.io.File;
53  import java.io.FileNotFoundException;
54  import java.io.FileOutputStream;
55  import java.io.IOException;
56  import java.io.OutputStream;
57  import java.security.NoSuchAlgorithmException;
58  import java.util.Collections;
59  import java.util.LinkedList;
60  import java.util.List;
61  
62  @Component(role = ContainerDescriptorHandler.class, hint = "swid-generator", instantiationStrategy = "per-lookup")
63  public class SwidContainerDescriptorHandler implements ContainerDescriptorHandler {
64    private static final List<String> DEFAULT_INCLUDES = Collections.singletonList("**/**");
65  
66    private static final String DEFAULT_TAG_PATH = "SWIDTAG";
67    private static final String DEFAULT_TAG_NAME = "swid-tag.xml";
68  
69    /**
70     * the calling project.
71     */
72    @Requirement
73    private MavenProject project;
74  
75    @Requirement
76    private Logger logger;
77  
78    /**
79     * 
80     * Location of the file.
81     */
82    @Parameter(defaultValue = "${project.build.directory}/generated-swid", property = "outputDir", required = true)
83    private File outputDirectory;
84  
85    @Parameter(defaultValue = DEFAULT_TAG_PATH, required = true)
86    private String tagPath;
87  
88    @Parameter(defaultValue = DEFAULT_TAG_NAME, required = true)
89    private String tagName;
90  
91    @Parameter
92    private List<String> includes;
93    @Parameter
94    private List<String> excludes;
95  
96    @Parameter
97    private List<Entity> entities;
98  
99    /**
100    * Get the set of inscluded files.
101    * 
102    * @return the includes
103    */
104   public String[] getIncludes() {
105     List<String> retval;
106     if (includes != null && !includes.isEmpty()) {
107       retval = includes;
108     } else {
109       retval = DEFAULT_INCLUDES;
110     }
111     return retval.toArray(new String[retval.size()]);
112   }
113 
114   /**
115    * Get the set of exscluded files.
116    * 
117    * @return the excludes
118    */
119   public String[] getExcludes() {
120     List<String> retval;
121     if (excludes != null && !excludes.isEmpty()) {
122       retval = excludes;
123     } else {
124       retval = Collections.emptyList();
125     }
126     return retval.toArray(new String[retval.size()]);
127   }
128 
129   /**
130    * Retrieves the directory to write the tag to when building it.
131    * 
132    * @return a file representing the tag output location
133    */
134   public File getTagOutputDirectory() {
135     return outputDirectory == null ? new File(project.getBuild().getDirectory(), "generated-swid") : outputDirectory;
136   }
137 
138   /**
139    * Retrieves the path for where the tag is stored. This path is considered a subdirectory relative
140    * to the software's installation lcoation.
141    * 
142    * @return the tagPath
143    */
144   public String getTagPath() {
145     return tagPath == null ? DEFAULT_TAG_PATH : tagPath;
146   }
147 
148   /**
149    * @return the tagName
150    */
151   public String getTagName() {
152     return tagName == null ? DEFAULT_TAG_NAME : tagName;
153   }
154 
155   /**
156    * Determine the path to the SWID tag file and create any directories in this path.
157    * 
158    * @return the tag file
159    * @throws ArchiverException
160    *           if an error occurred while creating directories
161    */
162   protected File getSwidTagFile() throws ArchiverException {
163 
164     // create the output directory
165     File retval = getTagOutputDirectory();
166     if (!retval.exists() && !retval.mkdirs()) {
167       throw new ArchiverException(
168           "Unable to create the directory specified by outputDirectory configuration parameter: " + retval.getPath());
169     }
170     //
171     // // create the tagPath
172     // String tagPath = getTagPath();
173     // retval = new File(retval, tagPath);
174     // if (!retval.exists()) {
175     // if (!retval.mkdirs()) {
176     // throw new ArchiverException(
177     // "Unable to create the directory specified by tagPath configuration parameter:
178     // "
179     // + retval.getPath());
180     // }
181     // }
182 
183     // now the tagFile
184     String tagName = getTagName();
185     retval = new File(retval, tagName);
186     return retval;
187   }
188 
189   @Override
190   public void finalizeArchiveCreation(Archiver archiver) throws ArchiverException {
191     Log log = new DefaultLog(logger);
192     // make a SWID tag
193 
194     // determine what files to tag in the payload
195     ArchiveEntryFileEntryProcessortryFileEntryProcessor.html#ArchiveEntryFileEntryProcessor">ArchiveEntryFileEntryProcessor processor = new ArchiveEntryFileEntryProcessor(project, log);
196     processor.setIncludes(getIncludes());
197     processor.setExcludes(getExcludes());
198 
199     List<FileEntry> swidFiles;
200     try {
201       List<ArchiveEntry> entries = new LinkedList<>();
202       archiver.getResources().forEachRemaining(ae -> entries.add(ae));
203       swidFiles = processor.process(entries);
204     } catch (IOException e) {
205       throw new ArchiverException("An error occured while processing build files", e);
206     }
207     for (FileEntry entry : swidFiles) {
208       log.debug("Found file: " + entry.getPath() + " as: " + entry.getOutputRelativePath());
209     }
210 
211     // build the SWID Tag
212     String archiveLocation = getTagPath() + File.separator + getTagName();
213     SWIDBuilder builder;
214     try {
215       builder = MavenProjectSwidBuilderHelper.buildSwidTag(project, archiveLocation, this.entities, swidFiles);
216     } catch (NoSuchAlgorithmException e) {
217       throw new ArchiverException("A requested hash algorithm is not supported.", e);
218     } catch (IOException e) {
219       throw new ArchiverException("Unable to read file while building a SWID tag.", e);
220     }
221 
222     // Output the tag to a file
223     File tagFile = getSwidTagFile();
224 
225     try (OutputStream os = new BufferedOutputStream(new FileOutputStream(tagFile))) {
226       XMLOutputHandler handler = new XMLOutputHandler();
227       handler.write(builder, os);
228     } catch (FileNotFoundException e) {
229       throw new ArchiverException(e.getMessage());
230     } catch (IOException e) {
231       throw new ArchiverException(e.getMessage());
232     } catch (ValidationException e) {
233       throw new ArchiverException(e.getMessage());
234     }
235 
236     log.info("Adding tag to archive: " + tagFile.getAbsolutePath());
237     archiver.addFile(tagFile, archiveLocation);
238 
239   }
240 
241   @Override
242   public void finalizeArchiveExtraction(UnArchiver unarchiver) throws ArchiverException {
243     // Do nothing
244   }
245 
246   @Override
247   public List<?> getVirtualFiles() {
248     // no virtual files
249     return null;
250   }
251 
252   @Override
253   public boolean isSelected(FileInfo fileInfo) throws IOException {
254     // accept all resources
255     return true;
256   }
257 
258 }